@cosmos.gl/graph 2.3.1-beta.1 → 2.4.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/.eslintrc +61 -0
- package/CHARTER.md +69 -0
- package/GOVERNANCE.md +21 -0
- package/dist/index.d.ts +46 -15
- package/dist/index.js +2986 -2701
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +180 -62
- package/dist/index.min.js.map +1 -1
- package/dist/modules/GraphData/index.d.ts +18 -2
- package/dist/modules/Points/atlas-utils.d.ts +24 -0
- package/dist/modules/Points/index.d.ts +21 -2
- package/dist/modules/Store/index.d.ts +6 -1
- package/dist/stories/create-story.d.ts +5 -1
- package/dist/stories/shapes/image-example/index.d.ts +5 -0
- package/dist/stories/shapes.stories.d.ts +1 -0
- package/package.json +4 -4
- package/src/config.ts +1 -0
- package/src/declaration.d.ts +5 -0
- package/src/index.ts +119 -67
- package/src/modules/GraphData/index.ts +68 -6
- package/src/modules/Points/atlas-utils.ts +137 -0
- package/src/modules/Points/draw-highlighted.vert +3 -3
- package/src/modules/Points/draw-points.frag +106 -14
- package/src/modules/Points/draw-points.vert +51 -25
- package/src/modules/Points/find-points-on-area-selection.frag +6 -5
- package/src/modules/Points/index.ts +121 -13
- package/src/modules/Store/index.ts +11 -3
- package/src/stories/3. api-reference.mdx +48 -1
- package/src/stories/create-story.ts +32 -5
- package/src/stories/shapes/image-example/icons/box.png +0 -0
- package/src/stories/shapes/image-example/icons/lego.png +0 -0
- package/src/stories/shapes/image-example/icons/s.png +0 -0
- package/src/stories/shapes/image-example/icons/swift.png +0 -0
- package/src/stories/shapes/image-example/icons/toolbox.png +0 -0
- package/src/stories/shapes/image-example/index.ts +239 -0
- package/src/stories/shapes.stories.ts +12 -0
|
@@ -7,13 +7,17 @@ export declare enum PointShape {
|
|
|
7
7
|
Pentagon = 4,
|
|
8
8
|
Hexagon = 5,
|
|
9
9
|
Star = 6,
|
|
10
|
-
Cross = 7
|
|
10
|
+
Cross = 7,
|
|
11
|
+
None = 8
|
|
11
12
|
}
|
|
12
13
|
export declare class GraphData {
|
|
13
14
|
inputPointPositions: Float32Array | undefined;
|
|
14
15
|
inputPointColors: Float32Array | undefined;
|
|
15
16
|
inputPointSizes: Float32Array | undefined;
|
|
16
17
|
inputPointShapes: Float32Array | undefined;
|
|
18
|
+
inputImageData: ImageData[] | undefined;
|
|
19
|
+
inputPointImageIndices: Float32Array | undefined;
|
|
20
|
+
inputPointImageSizes: Float32Array | undefined;
|
|
17
21
|
inputLinkColors: Float32Array | undefined;
|
|
18
22
|
inputLinkWidths: Float32Array | undefined;
|
|
19
23
|
inputLinkStrength: Float32Array | undefined;
|
|
@@ -24,6 +28,8 @@ export declare class GraphData {
|
|
|
24
28
|
pointColors: Float32Array | undefined;
|
|
25
29
|
pointSizes: Float32Array | undefined;
|
|
26
30
|
pointShapes: Float32Array | undefined;
|
|
31
|
+
pointImageIndices: Float32Array | undefined;
|
|
32
|
+
pointImageSizes: Float32Array | undefined;
|
|
27
33
|
inputLinks: Float32Array | undefined;
|
|
28
34
|
links: Float32Array | undefined;
|
|
29
35
|
linkColors: Float32Array | undefined;
|
|
@@ -58,9 +64,19 @@ export declare class GraphData {
|
|
|
58
64
|
*/
|
|
59
65
|
updatePointSize(): void;
|
|
60
66
|
/**
|
|
61
|
-
* Updates the point shapes based on the input data or default shape
|
|
67
|
+
* Updates the point shapes based on the input data or default shape.
|
|
68
|
+
* Default behavior: Circle (0).
|
|
69
|
+
* Images are rendered above shapes.
|
|
62
70
|
*/
|
|
63
71
|
updatePointShape(): void;
|
|
72
|
+
/**
|
|
73
|
+
* Updates the point image indices based on the input data or default value (-1 for no image).
|
|
74
|
+
*/
|
|
75
|
+
updatePointImageIndices(): void;
|
|
76
|
+
/**
|
|
77
|
+
* Updates the point image sizes based on the input data or default to point sizes.
|
|
78
|
+
*/
|
|
79
|
+
updatePointImageSizes(): void;
|
|
64
80
|
updateLinks(): void;
|
|
65
81
|
/**
|
|
66
82
|
* Updates the link colors based on the input data or default config value.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a texture atlas from an array of ImageData objects.
|
|
3
|
+
*
|
|
4
|
+
* A texture atlas is a single large texture that contains multiple smaller images.
|
|
5
|
+
* This allows efficient rendering by reducing the number of texture bindings needed.
|
|
6
|
+
*
|
|
7
|
+
* The atlas uses a grid layout where each image gets a square region sized to
|
|
8
|
+
* accommodate the largest image dimension. Images are placed left-to-right, top-to-bottom.
|
|
9
|
+
*
|
|
10
|
+
* @param imageDataArray - Array of ImageData objects to pack into the atlas
|
|
11
|
+
* @param webglMaxTextureSize - WebGL maximum texture size limit (default: 16384)
|
|
12
|
+
* @returns Atlas data object containing:
|
|
13
|
+
* - atlasData: RGBA pixel data as Uint8Array
|
|
14
|
+
* - atlasSize: Total atlas texture size in pixels
|
|
15
|
+
* - atlasCoords: UV coordinates for each image as Float32Array
|
|
16
|
+
* - atlasCoordsSize: Grid size (number of rows/columns)
|
|
17
|
+
* Returns null if creation fails or no valid images provided
|
|
18
|
+
*/
|
|
19
|
+
export declare function createAtlasDataFromImageData(imageDataArray: ImageData[], webglMaxTextureSize?: number): {
|
|
20
|
+
atlasData: Uint8Array;
|
|
21
|
+
atlasSize: number;
|
|
22
|
+
atlasCoords: Float32Array;
|
|
23
|
+
atlasCoordsSize: number;
|
|
24
|
+
} | null;
|
|
@@ -9,14 +9,22 @@ export declare class Points extends CoreModule {
|
|
|
9
9
|
greyoutStatusFbo: regl.Framebuffer2D | undefined;
|
|
10
10
|
scaleX: ((x: number) => number) | undefined;
|
|
11
11
|
scaleY: ((y: number) => number) | undefined;
|
|
12
|
-
|
|
12
|
+
shouldSkipRescale: boolean | undefined;
|
|
13
|
+
imageAtlasTexture: regl.Texture2D | undefined;
|
|
14
|
+
imageCount: number;
|
|
13
15
|
private colorBuffer;
|
|
14
16
|
private sizeFbo;
|
|
15
17
|
private sizeBuffer;
|
|
16
18
|
private shapeBuffer;
|
|
19
|
+
private imageIndicesBuffer;
|
|
20
|
+
private imageSizesBuffer;
|
|
21
|
+
private imageAtlasCoordsTexture;
|
|
22
|
+
private imageAtlasCoordsTextureSize;
|
|
17
23
|
private trackedIndicesFbo;
|
|
18
24
|
private trackedPositionsFbo;
|
|
19
25
|
private sampledPointsFbo;
|
|
26
|
+
private trackedPositions;
|
|
27
|
+
private isPositionsUpToDate;
|
|
20
28
|
private drawCommand;
|
|
21
29
|
private drawHighlightedCommand;
|
|
22
30
|
private updatePositionCommand;
|
|
@@ -45,6 +53,9 @@ export declare class Points extends CoreModule {
|
|
|
45
53
|
updateGreyoutStatus(): void;
|
|
46
54
|
updateSize(): void;
|
|
47
55
|
updateShape(): void;
|
|
56
|
+
updateImageIndices(): void;
|
|
57
|
+
updateImageSizes(): void;
|
|
58
|
+
createAtlas(): void;
|
|
48
59
|
updateSampledPointsGrid(): void;
|
|
49
60
|
trackPoints(): void;
|
|
50
61
|
draw(): void;
|
|
@@ -55,7 +66,15 @@ export declare class Points extends CoreModule {
|
|
|
55
66
|
updatePolygonPath(polygonPath: [number, number][]): void;
|
|
56
67
|
findHoveredPoint(): void;
|
|
57
68
|
trackPointsByIndices(indices?: number[] | undefined): void;
|
|
58
|
-
|
|
69
|
+
/**
|
|
70
|
+
* Get current X and Y coordinates of the tracked points.
|
|
71
|
+
*
|
|
72
|
+
* When the simulation is disabled or stopped, this method returns a cached
|
|
73
|
+
* result to avoid expensive GPU-to-CPU memory transfers (`readPixels`).
|
|
74
|
+
*
|
|
75
|
+
* @returns A ReadonlyMap where keys are point indices and values are [x, y] coordinates.
|
|
76
|
+
*/
|
|
77
|
+
getTrackedPositionsMap(): ReadonlyMap<number, [number, number]>;
|
|
59
78
|
getSampledPointPositionsMap(): Map<number, [number, number]>;
|
|
60
79
|
getSampledPoints(): {
|
|
61
80
|
indices: number[];
|
|
@@ -27,10 +27,11 @@ export declare class Store {
|
|
|
27
27
|
adjustedSpaceSize: number;
|
|
28
28
|
isSpaceKeyPressed: boolean;
|
|
29
29
|
div: HTMLDivElement | undefined;
|
|
30
|
+
webglMaxTextureSize: number;
|
|
30
31
|
hoveredPointRingColor: number[];
|
|
31
32
|
focusedPointRingColor: number[];
|
|
32
33
|
greyoutPointColor: number[];
|
|
33
|
-
|
|
34
|
+
isDarkenGreyout: boolean;
|
|
34
35
|
private alphaTarget;
|
|
35
36
|
private scalePointX;
|
|
36
37
|
private scalePointY;
|
|
@@ -45,6 +46,10 @@ export declare class Store {
|
|
|
45
46
|
* it reduces the space size without changing the config parameter.
|
|
46
47
|
*/
|
|
47
48
|
adjustSpaceSize(configSpaceSize: number, webglMaxTextureSize: number): void;
|
|
49
|
+
/**
|
|
50
|
+
* Sets the WebGL texture size limit for use in atlas creation and other texture operations.
|
|
51
|
+
*/
|
|
52
|
+
setWebGLMaxTextureSize(webglMaxTextureSize: number): void;
|
|
48
53
|
updateScreenSize(width: number, height: number): void;
|
|
49
54
|
scaleX(x: number): number;
|
|
50
55
|
scaleY(y: number): number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cosmos.gl/graph",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "GPU-based force graph layout and rendering",
|
|
5
5
|
"jsdelivr": "dist/index.min.js",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -54,11 +54,11 @@
|
|
|
54
54
|
"@types/d3-transition": "^3.0.1",
|
|
55
55
|
"@types/d3-zoom": "^3.0.1",
|
|
56
56
|
"@types/dompurify": "^3.0.5",
|
|
57
|
-
"@typescript-eslint/eslint-plugin": "^
|
|
58
|
-
"@typescript-eslint/parser": "^
|
|
57
|
+
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
|
58
|
+
"@typescript-eslint/parser": "^6.21.0",
|
|
59
59
|
"@zerollup/ts-transform-paths": "^1.7.18",
|
|
60
60
|
"d3-scale-chromatic": "^3.1.0",
|
|
61
|
-
"eslint": "^8.
|
|
61
|
+
"eslint": "^8.57.1",
|
|
62
62
|
"eslint-config-standard": "^17.0.0",
|
|
63
63
|
"eslint-plugin-import": "^2.26.0",
|
|
64
64
|
"eslint-plugin-node": "^11.1.0",
|
package/src/config.ts
CHANGED
package/src/declaration.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
declare module '*.frag';
|
|
2
2
|
declare module '*.vert';
|
|
3
|
+
declare module '*.png' {
|
|
4
|
+
const content: string
|
|
5
|
+
// eslint-disable-next-line import/no-default-export
|
|
6
|
+
export default content
|
|
7
|
+
}
|
|
3
8
|
declare module '*?raw' {
|
|
4
9
|
const content: string
|
|
5
10
|
// eslint-disable-next-line import/no-default-export
|
package/src/index.ts
CHANGED
|
@@ -64,18 +64,20 @@ export class Graph {
|
|
|
64
64
|
private _isFirstRenderAfterInit = true
|
|
65
65
|
private _fitViewOnInitTimeoutID: number | undefined
|
|
66
66
|
|
|
67
|
-
private
|
|
68
|
-
private
|
|
69
|
-
private
|
|
70
|
-
private
|
|
71
|
-
private
|
|
72
|
-
private
|
|
73
|
-
private
|
|
74
|
-
private
|
|
75
|
-
private
|
|
76
|
-
private
|
|
77
|
-
private
|
|
78
|
-
private
|
|
67
|
+
private isPointPositionsUpdateNeeded = false
|
|
68
|
+
private isPointColorUpdateNeeded = false
|
|
69
|
+
private isPointSizeUpdateNeeded = false
|
|
70
|
+
private isPointShapeUpdateNeeded = false
|
|
71
|
+
private isPointImageIndicesUpdateNeeded = false
|
|
72
|
+
private isLinksUpdateNeeded = false
|
|
73
|
+
private isLinkColorUpdateNeeded = false
|
|
74
|
+
private isLinkWidthUpdateNeeded = false
|
|
75
|
+
private isLinkArrowUpdateNeeded = false
|
|
76
|
+
private isPointClusterUpdateNeeded = false
|
|
77
|
+
private isForceManyBodyUpdateNeeded = false
|
|
78
|
+
private isForceLinkUpdateNeeded = false
|
|
79
|
+
private isForceCenterUpdateNeeded = false
|
|
80
|
+
private isPointImageSizesUpdateNeeded = false
|
|
79
81
|
|
|
80
82
|
private _isDestroyed = false
|
|
81
83
|
|
|
@@ -114,6 +116,7 @@ export class Graph {
|
|
|
114
116
|
this.reglInstance = reglInstance
|
|
115
117
|
|
|
116
118
|
this.store.adjustSpaceSize(this.config.spaceSize, this.reglInstance.limits.maxTextureSize)
|
|
119
|
+
this.store.setWebGLMaxTextureSize(this.reglInstance.limits.maxTextureSize)
|
|
117
120
|
this.store.updateScreenSize(w, h)
|
|
118
121
|
|
|
119
122
|
this.canvasD3Selection = select<HTMLCanvasElement, undefined>(this.canvas)
|
|
@@ -297,18 +300,19 @@ export class Graph {
|
|
|
297
300
|
public setPointPositions (pointPositions: Float32Array, dontRescale?: boolean | undefined): void {
|
|
298
301
|
if (this._isDestroyed || !this.points) return
|
|
299
302
|
this.graph.inputPointPositions = pointPositions
|
|
300
|
-
this.points.
|
|
301
|
-
this.
|
|
303
|
+
this.points.shouldSkipRescale = dontRescale
|
|
304
|
+
this.isPointPositionsUpdateNeeded = true
|
|
302
305
|
// Links related texture depends on point positions, so we need to update it
|
|
303
|
-
this.
|
|
306
|
+
this.isLinksUpdateNeeded = true
|
|
304
307
|
// Point related textures depend on point positions length, so we need to update them
|
|
305
|
-
this.
|
|
306
|
-
this.
|
|
307
|
-
this.
|
|
308
|
-
this.
|
|
309
|
-
this.
|
|
310
|
-
this.
|
|
311
|
-
this.
|
|
308
|
+
this.isPointColorUpdateNeeded = true
|
|
309
|
+
this.isPointSizeUpdateNeeded = true
|
|
310
|
+
this.isPointShapeUpdateNeeded = true
|
|
311
|
+
this.isPointImageIndicesUpdateNeeded = true
|
|
312
|
+
this.isPointClusterUpdateNeeded = true
|
|
313
|
+
this.isForceManyBodyUpdateNeeded = true
|
|
314
|
+
this.isForceLinkUpdateNeeded = true
|
|
315
|
+
this.isForceCenterUpdateNeeded = true
|
|
312
316
|
}
|
|
313
317
|
|
|
314
318
|
/**
|
|
@@ -321,7 +325,7 @@ export class Graph {
|
|
|
321
325
|
public setPointColors (pointColors: Float32Array): void {
|
|
322
326
|
if (this._isDestroyed) return
|
|
323
327
|
this.graph.inputPointColors = pointColors
|
|
324
|
-
this.
|
|
328
|
+
this.isPointColorUpdateNeeded = true
|
|
325
329
|
}
|
|
326
330
|
|
|
327
331
|
/**
|
|
@@ -345,7 +349,7 @@ export class Graph {
|
|
|
345
349
|
public setPointSizes (pointSizes: Float32Array): void {
|
|
346
350
|
if (this._isDestroyed) return
|
|
347
351
|
this.graph.inputPointSizes = pointSizes
|
|
348
|
-
this.
|
|
352
|
+
this.isPointSizeUpdateNeeded = true
|
|
349
353
|
}
|
|
350
354
|
|
|
351
355
|
/**
|
|
@@ -353,13 +357,55 @@ export class Graph {
|
|
|
353
357
|
*
|
|
354
358
|
* @param {Float32Array} pointShapes - A Float32Array representing the shapes of points in the format [shape1, shape2, ..., shapen],
|
|
355
359
|
* where `n` is the index of the point and each shape value corresponds to a PointShape enum:
|
|
356
|
-
* 0 = Circle, 1 = Square, 2 = Triangle, 3 = Diamond, 4 = Pentagon, 5 = Hexagon, 6 = Star, 7 = Cross.
|
|
360
|
+
* 0 = Circle, 1 = Square, 2 = Triangle, 3 = Diamond, 4 = Pentagon, 5 = Hexagon, 6 = Star, 7 = Cross, 8 = None.
|
|
357
361
|
* Example: `new Float32Array([0, 1, 2])` sets the first point to Circle, the second point to Square, and the third point to Triangle.
|
|
362
|
+
* Images are rendered above shapes.
|
|
358
363
|
*/
|
|
359
364
|
public setPointShapes (pointShapes: Float32Array): void {
|
|
360
365
|
if (this._isDestroyed) return
|
|
361
366
|
this.graph.inputPointShapes = pointShapes
|
|
362
|
-
this.
|
|
367
|
+
this.isPointShapeUpdateNeeded = true
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Sets the images for the graph points using ImageData objects.
|
|
372
|
+
* Images are rendered above shapes.
|
|
373
|
+
* To use images, provide image indices via setPointImageIndices().
|
|
374
|
+
*
|
|
375
|
+
* @param {ImageData[]} imageDataArray - Array of ImageData objects to use as point images.
|
|
376
|
+
* Example: `setImageData([imageData1, imageData2, imageData3])`
|
|
377
|
+
*/
|
|
378
|
+
public setImageData (imageDataArray: ImageData[]): void {
|
|
379
|
+
if (this._isDestroyed || !this.points) return
|
|
380
|
+
this.graph.inputImageData = imageDataArray
|
|
381
|
+
this.points.createAtlas()
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Sets which image each point should use from the images array.
|
|
386
|
+
* Images are rendered above shapes.
|
|
387
|
+
*
|
|
388
|
+
* @param {Float32Array} imageIndices - A Float32Array representing which image each point uses in the format [index1, index2, ..., indexn],
|
|
389
|
+
* where `n` is the index of the point and each value is an index into the images array provided to `setImageData`.
|
|
390
|
+
* Example: `new Float32Array([0, 1, 0])` sets the first point to use image 0, second point to use image 1, third point to use image 0.
|
|
391
|
+
*/
|
|
392
|
+
public setPointImageIndices (imageIndices: Float32Array): void {
|
|
393
|
+
if (this._isDestroyed) return
|
|
394
|
+
this.graph.inputPointImageIndices = imageIndices
|
|
395
|
+
this.isPointImageIndicesUpdateNeeded = true
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
* Sets the sizes for the point images.
|
|
400
|
+
*
|
|
401
|
+
* @param {Float32Array} imageSizes - A Float32Array representing the sizes of point images in the format [size1, size2, ..., sizen],
|
|
402
|
+
* where `n` is the index of the point.
|
|
403
|
+
* Example: `new Float32Array([10, 20, 30])` sets the first image to size 10, the second image to size 20, and the third image to size 30.
|
|
404
|
+
*/
|
|
405
|
+
public setPointImageSizes (imageSizes: Float32Array): void {
|
|
406
|
+
if (this._isDestroyed) return
|
|
407
|
+
this.graph.inputPointImageSizes = imageSizes
|
|
408
|
+
this.isPointImageSizesUpdateNeeded = true
|
|
363
409
|
}
|
|
364
410
|
|
|
365
411
|
/**
|
|
@@ -384,12 +430,12 @@ export class Graph {
|
|
|
384
430
|
public setLinks (links: Float32Array): void {
|
|
385
431
|
if (this._isDestroyed) return
|
|
386
432
|
this.graph.inputLinks = links
|
|
387
|
-
this.
|
|
433
|
+
this.isLinksUpdateNeeded = true
|
|
388
434
|
// Links related texture depends on links length, so we need to update it
|
|
389
|
-
this.
|
|
390
|
-
this.
|
|
391
|
-
this.
|
|
392
|
-
this.
|
|
435
|
+
this.isLinkColorUpdateNeeded = true
|
|
436
|
+
this.isLinkWidthUpdateNeeded = true
|
|
437
|
+
this.isLinkArrowUpdateNeeded = true
|
|
438
|
+
this.isForceLinkUpdateNeeded = true
|
|
393
439
|
}
|
|
394
440
|
|
|
395
441
|
/**
|
|
@@ -402,7 +448,7 @@ export class Graph {
|
|
|
402
448
|
public setLinkColors (linkColors: Float32Array): void {
|
|
403
449
|
if (this._isDestroyed) return
|
|
404
450
|
this.graph.inputLinkColors = linkColors
|
|
405
|
-
this.
|
|
451
|
+
this.isLinkColorUpdateNeeded = true
|
|
406
452
|
}
|
|
407
453
|
|
|
408
454
|
/**
|
|
@@ -426,7 +472,7 @@ export class Graph {
|
|
|
426
472
|
public setLinkWidths (linkWidths: Float32Array): void {
|
|
427
473
|
if (this._isDestroyed) return
|
|
428
474
|
this.graph.inputLinkWidths = linkWidths
|
|
429
|
-
this.
|
|
475
|
+
this.isLinkWidthUpdateNeeded = true
|
|
430
476
|
}
|
|
431
477
|
|
|
432
478
|
/**
|
|
@@ -450,7 +496,7 @@ export class Graph {
|
|
|
450
496
|
public setLinkArrows (linkArrows: boolean[]): void {
|
|
451
497
|
if (this._isDestroyed) return
|
|
452
498
|
this.graph.linkArrowsBoolean = linkArrows
|
|
453
|
-
this.
|
|
499
|
+
this.isLinkArrowUpdateNeeded = true
|
|
454
500
|
}
|
|
455
501
|
|
|
456
502
|
/**
|
|
@@ -463,7 +509,7 @@ export class Graph {
|
|
|
463
509
|
public setLinkStrength (linkStrength: Float32Array): void {
|
|
464
510
|
if (this._isDestroyed) return
|
|
465
511
|
this.graph.inputLinkStrength = linkStrength
|
|
466
|
-
this.
|
|
512
|
+
this.isForceLinkUpdateNeeded = true
|
|
467
513
|
}
|
|
468
514
|
|
|
469
515
|
/**
|
|
@@ -480,7 +526,7 @@ export class Graph {
|
|
|
480
526
|
public setPointClusters (pointClusters: (number | undefined)[]): void {
|
|
481
527
|
if (this._isDestroyed) return
|
|
482
528
|
this.graph.inputPointClusters = pointClusters
|
|
483
|
-
this.
|
|
529
|
+
this.isPointClusterUpdateNeeded = true
|
|
484
530
|
}
|
|
485
531
|
|
|
486
532
|
/**
|
|
@@ -496,7 +542,7 @@ export class Graph {
|
|
|
496
542
|
public setClusterPositions (clusterPositions: (number | undefined)[]): void {
|
|
497
543
|
if (this._isDestroyed) return
|
|
498
544
|
this.graph.inputClusterPositions = clusterPositions
|
|
499
|
-
this.
|
|
545
|
+
this.isPointClusterUpdateNeeded = true
|
|
500
546
|
}
|
|
501
547
|
|
|
502
548
|
/**
|
|
@@ -512,7 +558,7 @@ export class Graph {
|
|
|
512
558
|
public setPointClusterStrength (clusterStrength: Float32Array): void {
|
|
513
559
|
if (this._isDestroyed) return
|
|
514
560
|
this.graph.inputClusterStrength = clusterStrength
|
|
515
|
-
this.
|
|
561
|
+
this.isPointClusterUpdateNeeded = true
|
|
516
562
|
}
|
|
517
563
|
|
|
518
564
|
/**
|
|
@@ -936,9 +982,11 @@ export class Graph {
|
|
|
936
982
|
|
|
937
983
|
/**
|
|
938
984
|
* Get current X and Y coordinates of the tracked points.
|
|
939
|
-
*
|
|
985
|
+
* Do not mutate the returned map - it may affect future calls.
|
|
986
|
+
* @returns A ReadonlyMap where keys are point indices and values are their corresponding X and Y coordinates in the [number, number] format.
|
|
987
|
+
* @see trackPointPositionsByIndices To set which points should be tracked
|
|
940
988
|
*/
|
|
941
|
-
public getTrackedPointPositionsMap ():
|
|
989
|
+
public getTrackedPointPositionsMap (): ReadonlyMap<number, [number, number]> {
|
|
942
990
|
if (this._isDestroyed || !this.points) return new Map()
|
|
943
991
|
return this.points.getTrackedPositionsMap()
|
|
944
992
|
}
|
|
@@ -1114,36 +1162,40 @@ export class Graph {
|
|
|
1114
1162
|
*/
|
|
1115
1163
|
public create (): void {
|
|
1116
1164
|
if (this._isDestroyed || !this.points || !this.lines) return
|
|
1117
|
-
if (this.
|
|
1118
|
-
if (this.
|
|
1119
|
-
if (this.
|
|
1120
|
-
if (this.
|
|
1121
|
-
|
|
1122
|
-
if (this.
|
|
1123
|
-
|
|
1124
|
-
if (this.
|
|
1125
|
-
if (this.
|
|
1126
|
-
|
|
1127
|
-
if (this.
|
|
1128
|
-
|
|
1165
|
+
if (this.isPointPositionsUpdateNeeded) this.points.updatePositions()
|
|
1166
|
+
if (this.isPointColorUpdateNeeded) this.points.updateColor()
|
|
1167
|
+
if (this.isPointSizeUpdateNeeded) this.points.updateSize()
|
|
1168
|
+
if (this.isPointShapeUpdateNeeded) this.points.updateShape()
|
|
1169
|
+
if (this.isPointImageIndicesUpdateNeeded) this.points.updateImageIndices()
|
|
1170
|
+
if (this.isPointImageSizesUpdateNeeded) this.points.updateImageSizes()
|
|
1171
|
+
|
|
1172
|
+
if (this.isLinksUpdateNeeded) this.lines.updatePointsBuffer()
|
|
1173
|
+
if (this.isLinkColorUpdateNeeded) this.lines.updateColor()
|
|
1174
|
+
if (this.isLinkWidthUpdateNeeded) this.lines.updateWidth()
|
|
1175
|
+
if (this.isLinkArrowUpdateNeeded) this.lines.updateArrow()
|
|
1176
|
+
|
|
1177
|
+
if (this.isForceManyBodyUpdateNeeded) this.forceManyBody?.create()
|
|
1178
|
+
if (this.isForceLinkUpdateNeeded) {
|
|
1129
1179
|
this.forceLinkIncoming?.create(LinkDirection.INCOMING)
|
|
1130
1180
|
this.forceLinkOutgoing?.create(LinkDirection.OUTGOING)
|
|
1131
1181
|
}
|
|
1132
|
-
if (this.
|
|
1133
|
-
if (this.
|
|
1134
|
-
|
|
1135
|
-
this.
|
|
1136
|
-
this.
|
|
1137
|
-
this.
|
|
1138
|
-
this.
|
|
1139
|
-
this.
|
|
1140
|
-
this.
|
|
1141
|
-
this.
|
|
1142
|
-
this.
|
|
1143
|
-
this.
|
|
1144
|
-
this.
|
|
1145
|
-
this.
|
|
1146
|
-
this.
|
|
1182
|
+
if (this.isForceCenterUpdateNeeded) this.forceCenter?.create()
|
|
1183
|
+
if (this.isPointClusterUpdateNeeded) this.clusters?.create()
|
|
1184
|
+
|
|
1185
|
+
this.isPointPositionsUpdateNeeded = false
|
|
1186
|
+
this.isPointColorUpdateNeeded = false
|
|
1187
|
+
this.isPointSizeUpdateNeeded = false
|
|
1188
|
+
this.isPointShapeUpdateNeeded = false
|
|
1189
|
+
this.isPointImageIndicesUpdateNeeded = false
|
|
1190
|
+
this.isPointImageSizesUpdateNeeded = false
|
|
1191
|
+
this.isLinksUpdateNeeded = false
|
|
1192
|
+
this.isLinkColorUpdateNeeded = false
|
|
1193
|
+
this.isLinkWidthUpdateNeeded = false
|
|
1194
|
+
this.isLinkArrowUpdateNeeded = false
|
|
1195
|
+
this.isPointClusterUpdateNeeded = false
|
|
1196
|
+
this.isForceManyBodyUpdateNeeded = false
|
|
1197
|
+
this.isForceLinkUpdateNeeded = false
|
|
1198
|
+
this.isForceCenterUpdateNeeded = false
|
|
1147
1199
|
}
|
|
1148
1200
|
|
|
1149
1201
|
/**
|
|
@@ -9,7 +9,8 @@ export enum PointShape {
|
|
|
9
9
|
Pentagon = 4,
|
|
10
10
|
Hexagon = 5,
|
|
11
11
|
Star = 6,
|
|
12
|
-
Cross = 7
|
|
12
|
+
Cross = 7,
|
|
13
|
+
None = 8
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export class GraphData {
|
|
@@ -17,6 +18,9 @@ export class GraphData {
|
|
|
17
18
|
public inputPointColors: Float32Array | undefined
|
|
18
19
|
public inputPointSizes: Float32Array | undefined
|
|
19
20
|
public inputPointShapes: Float32Array | undefined
|
|
21
|
+
public inputImageData: ImageData[] | undefined
|
|
22
|
+
public inputPointImageIndices: Float32Array | undefined
|
|
23
|
+
public inputPointImageSizes: Float32Array | undefined
|
|
20
24
|
public inputLinkColors: Float32Array | undefined
|
|
21
25
|
public inputLinkWidths: Float32Array | undefined
|
|
22
26
|
public inputLinkStrength: Float32Array | undefined
|
|
@@ -28,6 +32,8 @@ export class GraphData {
|
|
|
28
32
|
public pointColors: Float32Array | undefined
|
|
29
33
|
public pointSizes: Float32Array | undefined
|
|
30
34
|
public pointShapes: Float32Array | undefined
|
|
35
|
+
public pointImageIndices: Float32Array | undefined
|
|
36
|
+
public pointImageSizes: Float32Array | undefined
|
|
31
37
|
|
|
32
38
|
public inputLinks: Float32Array | undefined
|
|
33
39
|
public links: Float32Array | undefined
|
|
@@ -124,7 +130,9 @@ export class GraphData {
|
|
|
124
130
|
}
|
|
125
131
|
|
|
126
132
|
/**
|
|
127
|
-
* Updates the point shapes based on the input data or default shape
|
|
133
|
+
* Updates the point shapes based on the input data or default shape.
|
|
134
|
+
* Default behavior: Circle (0).
|
|
135
|
+
* Images are rendered above shapes.
|
|
128
136
|
*/
|
|
129
137
|
public updatePointShape (): void {
|
|
130
138
|
if (this.pointsNumber === undefined) {
|
|
@@ -132,16 +140,68 @@ export class GraphData {
|
|
|
132
140
|
return
|
|
133
141
|
}
|
|
134
142
|
|
|
135
|
-
//
|
|
143
|
+
// Determine default shape: Circle
|
|
144
|
+
const defaultShape = PointShape.Circle
|
|
145
|
+
|
|
146
|
+
// Sets point shapes to default values if the input is missing or does not match input points number.
|
|
136
147
|
if (this.inputPointShapes === undefined || this.inputPointShapes.length !== this.pointsNumber) {
|
|
137
|
-
this.pointShapes = new Float32Array(this.pointsNumber).fill(
|
|
148
|
+
this.pointShapes = new Float32Array(this.pointsNumber).fill(defaultShape)
|
|
138
149
|
} else {
|
|
139
150
|
this.pointShapes = new Float32Array(this.inputPointShapes)
|
|
140
151
|
const pointShapes = this.pointShapes
|
|
141
152
|
for (let i = 0; i < pointShapes.length; i++) {
|
|
142
153
|
const shape = pointShapes[i]
|
|
143
|
-
if (shape == null || !isNumber(shape) || shape < 0 || shape >
|
|
144
|
-
pointShapes[i] =
|
|
154
|
+
if (shape == null || !isNumber(shape) || shape < 0 || shape > 8) {
|
|
155
|
+
pointShapes[i] = defaultShape
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Updates the point image indices based on the input data or default value (-1 for no image).
|
|
163
|
+
*/
|
|
164
|
+
public updatePointImageIndices (): void {
|
|
165
|
+
if (this.pointsNumber === undefined) {
|
|
166
|
+
this.pointImageIndices = undefined
|
|
167
|
+
return
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Sets point image indices to -1 if input is missing or doesn't match points count
|
|
171
|
+
if (this.inputPointImageIndices === undefined || this.inputPointImageIndices.length !== this.pointsNumber) {
|
|
172
|
+
this.pointImageIndices = new Float32Array(this.pointsNumber).fill(-1)
|
|
173
|
+
} else {
|
|
174
|
+
const pointImageIndices = new Float32Array(this.inputPointImageIndices)
|
|
175
|
+
for (let i = 0; i < pointImageIndices.length; i++) {
|
|
176
|
+
const rawIndex = pointImageIndices[i]
|
|
177
|
+
const imageIndex = (rawIndex === undefined) ? NaN : rawIndex
|
|
178
|
+
if (!Number.isFinite(imageIndex) || imageIndex < 0) {
|
|
179
|
+
pointImageIndices[i] = -1
|
|
180
|
+
} else {
|
|
181
|
+
pointImageIndices[i] = Math.trunc(imageIndex)
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
this.pointImageIndices = pointImageIndices
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Updates the point image sizes based on the input data or default to point sizes.
|
|
190
|
+
*/
|
|
191
|
+
public updatePointImageSizes (): void {
|
|
192
|
+
if (this.pointsNumber === undefined) {
|
|
193
|
+
this.pointImageSizes = undefined
|
|
194
|
+
return
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Sets point image sizes to point sizes if the input is missing or does not match input points number.
|
|
198
|
+
if (this.inputPointImageSizes === undefined || this.inputPointImageSizes.length !== this.pointsNumber) {
|
|
199
|
+
this.pointImageSizes = this.pointSizes ? new Float32Array(this.pointSizes) : new Float32Array(this.pointsNumber).fill(this._config.pointSize)
|
|
200
|
+
} else {
|
|
201
|
+
this.pointImageSizes = new Float32Array(this.inputPointImageSizes)
|
|
202
|
+
for (let i = 0; i < this.pointImageSizes.length; i++) {
|
|
203
|
+
if (!isNumber(this.pointImageSizes[i])) {
|
|
204
|
+
this.pointImageSizes[i] = this.pointSizes?.[i] ?? this._config.pointSize
|
|
145
205
|
}
|
|
146
206
|
}
|
|
147
207
|
}
|
|
@@ -261,6 +321,8 @@ export class GraphData {
|
|
|
261
321
|
this.updatePointColor()
|
|
262
322
|
this.updatePointSize()
|
|
263
323
|
this.updatePointShape()
|
|
324
|
+
this.updatePointImageIndices()
|
|
325
|
+
this.updatePointImageSizes()
|
|
264
326
|
|
|
265
327
|
this.updateLinks()
|
|
266
328
|
this.updateLinkColor()
|