@cosmos.gl/graph 2.6.0 → 2.6.2-rc.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/dist/config.d.ts +3 -0
- package/dist/index.d.ts +48 -6
- package/dist/index.js +1346 -1289
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +15 -15
- package/dist/index.min.js.map +1 -1
- package/package.json +5 -1
- package/.eslintrc +0 -147
- package/.github/SECURITY.md +0 -19
- package/.github/dco.yml +0 -4
- package/.github/workflows/github_pages.yml +0 -54
- package/.storybook/main.ts +0 -26
- package/.storybook/manager-head.html +0 -1
- package/.storybook/manager.ts +0 -14
- package/.storybook/preview.ts +0 -29
- package/.storybook/style.css +0 -3
- package/CHARTER.md +0 -69
- package/CODE_OF_CONDUCT.md +0 -178
- package/CONTRIBUTING.md +0 -22
- package/GOVERNANCE.md +0 -21
- package/cosmos-2-0-migration-notes.md +0 -98
- package/cosmos_awesome.md +0 -96
- package/dist/stories/beginners/basic-set-up/data-gen.d.ts +0 -4
- package/dist/stories/beginners/basic-set-up/index.d.ts +0 -5
- package/dist/stories/beginners/link-hovering/data-generator.d.ts +0 -19
- package/dist/stories/beginners/link-hovering/index.d.ts +0 -5
- package/dist/stories/beginners/pinned-points/data-gen.d.ts +0 -5
- package/dist/stories/beginners/pinned-points/index.d.ts +0 -5
- package/dist/stories/beginners/point-labels/data.d.ts +0 -13
- package/dist/stories/beginners/point-labels/index.d.ts +0 -9
- package/dist/stories/beginners/point-labels/labels.d.ts +0 -8
- package/dist/stories/beginners/quick-start.d.ts +0 -5
- package/dist/stories/beginners/remove-points/config.d.ts +0 -2
- package/dist/stories/beginners/remove-points/data-gen.d.ts +0 -4
- package/dist/stories/beginners/remove-points/index.d.ts +0 -5
- package/dist/stories/beginners.stories.d.ts +0 -11
- package/dist/stories/clusters/polygon-selection/index.d.ts +0 -6
- package/dist/stories/clusters/polygon-selection/polygon.d.ts +0 -20
- package/dist/stories/clusters/radial.d.ts +0 -5
- package/dist/stories/clusters/with-labels.d.ts +0 -6
- package/dist/stories/clusters/worm.d.ts +0 -5
- package/dist/stories/clusters.stories.d.ts +0 -9
- package/dist/stories/create-cluster-labels.d.ts +0 -4
- package/dist/stories/create-cosmos.d.ts +0 -16
- package/dist/stories/create-story.d.ts +0 -16
- package/dist/stories/experiments/full-mesh.d.ts +0 -5
- package/dist/stories/experiments/mesh-with-holes.d.ts +0 -5
- package/dist/stories/experiments.stories.d.ts +0 -7
- package/dist/stories/generate-mesh-data.d.ts +0 -12
- package/dist/stories/geospatial/moscow-metro-stations/index.d.ts +0 -15
- package/dist/stories/geospatial/moscow-metro-stations/moscow-metro-coords.d.ts +0 -1
- package/dist/stories/geospatial/moscow-metro-stations/point-colors.d.ts +0 -1
- package/dist/stories/geospatial.stories.d.ts +0 -6
- package/dist/stories/shapes/all-shapes/index.d.ts +0 -5
- package/dist/stories/shapes/image-example/index.d.ts +0 -5
- package/dist/stories/shapes.stories.d.ts +0 -7
- package/logo.svg +0 -3
- package/rollup.config.js +0 -70
- package/src/config.ts +0 -734
- package/src/declaration.d.ts +0 -12
- package/src/graph/utils/error-message.ts +0 -23
- package/src/helper.ts +0 -74
- package/src/index.ts +0 -1635
- package/src/modules/Clusters/calculate-centermass.frag +0 -9
- package/src/modules/Clusters/calculate-centermass.vert +0 -26
- package/src/modules/Clusters/force-cluster.frag +0 -39
- package/src/modules/Clusters/index.ts +0 -200
- package/src/modules/Drag/index.ts +0 -33
- package/src/modules/FPSMonitor/css.ts +0 -53
- package/src/modules/FPSMonitor/index.ts +0 -28
- package/src/modules/ForceCenter/calculate-centermass.frag +0 -9
- package/src/modules/ForceCenter/calculate-centermass.vert +0 -18
- package/src/modules/ForceCenter/force-center.frag +0 -27
- package/src/modules/ForceCenter/index.ts +0 -104
- package/src/modules/ForceGravity/force-gravity.frag +0 -27
- package/src/modules/ForceGravity/index.ts +0 -33
- package/src/modules/ForceLink/force-spring.ts +0 -73
- package/src/modules/ForceLink/index.ts +0 -149
- package/src/modules/ForceManyBody/calculate-level.frag +0 -9
- package/src/modules/ForceManyBody/calculate-level.vert +0 -25
- package/src/modules/ForceManyBody/force-centermass.frag +0 -52
- package/src/modules/ForceManyBody/force-level.frag +0 -121
- package/src/modules/ForceManyBody/index.ts +0 -223
- package/src/modules/ForceManyBody/quadtree-frag-shader.ts +0 -90
- package/src/modules/ForceManyBodyQuadtree/calculate-level.frag +0 -9
- package/src/modules/ForceManyBodyQuadtree/calculate-level.vert +0 -25
- package/src/modules/ForceManyBodyQuadtree/index.ts +0 -157
- package/src/modules/ForceManyBodyQuadtree/quadtree-frag-shader.ts +0 -93
- package/src/modules/ForceMouse/force-mouse.frag +0 -24
- package/src/modules/ForceMouse/index.ts +0 -32
- package/src/modules/GraphData/index.ts +0 -384
- package/src/modules/Lines/draw-curve-line.frag +0 -46
- package/src/modules/Lines/draw-curve-line.vert +0 -194
- package/src/modules/Lines/geometry.ts +0 -18
- package/src/modules/Lines/hovered-line-index.frag +0 -27
- package/src/modules/Lines/hovered-line-index.vert +0 -8
- package/src/modules/Lines/index.ts +0 -273
- package/src/modules/Points/atlas-utils.ts +0 -137
- package/src/modules/Points/drag-point.frag +0 -20
- package/src/modules/Points/draw-highlighted.frag +0 -16
- package/src/modules/Points/draw-highlighted.vert +0 -86
- package/src/modules/Points/draw-points.frag +0 -243
- package/src/modules/Points/draw-points.vert +0 -127
- package/src/modules/Points/fill-sampled-points.frag +0 -9
- package/src/modules/Points/fill-sampled-points.vert +0 -29
- package/src/modules/Points/find-hovered-point.frag +0 -9
- package/src/modules/Points/find-hovered-point.vert +0 -57
- package/src/modules/Points/find-points-on-area-selection.frag +0 -48
- package/src/modules/Points/find-points-on-polygon-selection.frag +0 -65
- package/src/modules/Points/index.ts +0 -968
- package/src/modules/Points/track-positions.frag +0 -18
- package/src/modules/Points/update-position.frag +0 -37
- package/src/modules/Shared/buffer.ts +0 -37
- package/src/modules/Shared/clear.frag +0 -7
- package/src/modules/Shared/quad.vert +0 -12
- package/src/modules/Store/index.ts +0 -173
- package/src/modules/Zoom/index.ts +0 -148
- package/src/modules/core-module.ts +0 -28
- package/src/stories/1. welcome.mdx +0 -81
- package/src/stories/2. configuration.mdx +0 -113
- package/src/stories/3. api-reference.mdx +0 -591
- package/src/stories/beginners/basic-set-up/data-gen.ts +0 -33
- package/src/stories/beginners/basic-set-up/index.ts +0 -163
- package/src/stories/beginners/basic-set-up/style.css +0 -35
- package/src/stories/beginners/link-hovering/data-generator.ts +0 -198
- package/src/stories/beginners/link-hovering/index.ts +0 -61
- package/src/stories/beginners/link-hovering/style.css +0 -73
- package/src/stories/beginners/pinned-points/data-gen.ts +0 -153
- package/src/stories/beginners/pinned-points/index.ts +0 -61
- package/src/stories/beginners/point-labels/data.ts +0 -73
- package/src/stories/beginners/point-labels/index.ts +0 -65
- package/src/stories/beginners/point-labels/labels.ts +0 -46
- package/src/stories/beginners/point-labels/style.css +0 -16
- package/src/stories/beginners/quick-start.ts +0 -50
- package/src/stories/beginners/remove-points/config.ts +0 -25
- package/src/stories/beginners/remove-points/data-gen.ts +0 -30
- package/src/stories/beginners/remove-points/index.ts +0 -92
- package/src/stories/beginners/remove-points/style.css +0 -31
- package/src/stories/beginners.stories.ts +0 -131
- package/src/stories/clusters/polygon-selection/index.ts +0 -51
- package/src/stories/clusters/polygon-selection/polygon.ts +0 -143
- package/src/stories/clusters/polygon-selection/style.css +0 -8
- package/src/stories/clusters/radial.ts +0 -24
- package/src/stories/clusters/with-labels.ts +0 -53
- package/src/stories/clusters/worm.ts +0 -40
- package/src/stories/clusters.stories.ts +0 -77
- package/src/stories/create-cluster-labels.ts +0 -50
- package/src/stories/create-cosmos.ts +0 -68
- package/src/stories/create-story.ts +0 -51
- package/src/stories/experiments/full-mesh.ts +0 -13
- package/src/stories/experiments/mesh-with-holes.ts +0 -13
- package/src/stories/experiments.stories.ts +0 -43
- package/src/stories/generate-mesh-data.ts +0 -125
- package/src/stories/geospatial/moscow-metro-stations/index.ts +0 -62
- package/src/stories/geospatial/moscow-metro-stations/moscow-metro-coords.ts +0 -1
- package/src/stories/geospatial/moscow-metro-stations/point-colors.ts +0 -46
- package/src/stories/geospatial/moscow-metro-stations/style.css +0 -30
- package/src/stories/geospatial.stories.ts +0 -30
- package/src/stories/shapes/all-shapes/index.ts +0 -69
- 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 +0 -238
- package/src/stories/shapes.stories.ts +0 -37
- package/src/variables.ts +0 -68
- package/tsconfig.json +0 -41
- package/vite.config.ts +0 -54
|
@@ -1,968 +0,0 @@
|
|
|
1
|
-
import regl from 'regl'
|
|
2
|
-
// import { scaleLinear } from 'd3-scale'
|
|
3
|
-
// import { extent } from 'd3-array'
|
|
4
|
-
import { CoreModule } from '@/graph/modules/core-module'
|
|
5
|
-
import { defaultConfigValues } from '@/graph/variables'
|
|
6
|
-
import drawPointsFrag from '@/graph/modules/Points/draw-points.frag'
|
|
7
|
-
import drawPointsVert from '@/graph/modules/Points/draw-points.vert'
|
|
8
|
-
import findPointsOnAreaSelectionFrag from '@/graph/modules/Points/find-points-on-area-selection.frag'
|
|
9
|
-
import findPointsOnPolygonSelectionFrag from '@/graph/modules/Points/find-points-on-polygon-selection.frag'
|
|
10
|
-
import drawHighlightedFrag from '@/graph/modules/Points/draw-highlighted.frag'
|
|
11
|
-
import drawHighlightedVert from '@/graph/modules/Points/draw-highlighted.vert'
|
|
12
|
-
import findHoveredPointFrag from '@/graph/modules/Points/find-hovered-point.frag'
|
|
13
|
-
import findHoveredPointVert from '@/graph/modules/Points/find-hovered-point.vert'
|
|
14
|
-
import fillGridWithSampledPointsFrag from '@/graph/modules/Points/fill-sampled-points.frag'
|
|
15
|
-
import fillGridWithSampledPointsVert from '@/graph/modules/Points/fill-sampled-points.vert'
|
|
16
|
-
import updatePositionFrag from '@/graph/modules/Points/update-position.frag'
|
|
17
|
-
import { createIndexesForBuffer, createQuadBuffer } from '@/graph/modules/Shared/buffer'
|
|
18
|
-
import trackPositionsFrag from '@/graph/modules/Points/track-positions.frag'
|
|
19
|
-
import dragPointFrag from '@/graph/modules/Points/drag-point.frag'
|
|
20
|
-
import updateVert from '@/graph/modules/Shared/quad.vert'
|
|
21
|
-
import clearFrag from '@/graph/modules/Shared/clear.frag'
|
|
22
|
-
import { readPixels } from '@/graph/helper'
|
|
23
|
-
import { createAtlasDataFromImageData } from '@/graph/modules/Points/atlas-utils'
|
|
24
|
-
|
|
25
|
-
export class Points extends CoreModule {
|
|
26
|
-
public currentPositionFbo: regl.Framebuffer2D | undefined
|
|
27
|
-
public previousPositionFbo: regl.Framebuffer2D | undefined
|
|
28
|
-
public velocityFbo: regl.Framebuffer2D | undefined
|
|
29
|
-
public selectedFbo: regl.Framebuffer2D | undefined
|
|
30
|
-
public hoveredFbo: regl.Framebuffer2D | undefined
|
|
31
|
-
public greyoutStatusFbo: regl.Framebuffer2D | undefined
|
|
32
|
-
public scaleX: ((x: number) => number) | undefined
|
|
33
|
-
public scaleY: ((y: number) => number) | undefined
|
|
34
|
-
public shouldSkipRescale: boolean | undefined
|
|
35
|
-
public imageAtlasTexture: regl.Texture2D | undefined
|
|
36
|
-
public imageCount = 0
|
|
37
|
-
private colorBuffer: regl.Buffer | undefined
|
|
38
|
-
private sizeFbo: regl.Framebuffer2D | undefined
|
|
39
|
-
private sizeBuffer: regl.Buffer | undefined
|
|
40
|
-
private shapeBuffer: regl.Buffer | undefined
|
|
41
|
-
private imageIndicesBuffer: regl.Buffer | undefined
|
|
42
|
-
private imageSizesBuffer: regl.Buffer | undefined
|
|
43
|
-
private imageAtlasCoordsTexture: regl.Texture2D | undefined
|
|
44
|
-
private imageAtlasCoordsTextureSize: number | undefined
|
|
45
|
-
private trackedIndicesFbo: regl.Framebuffer2D | undefined
|
|
46
|
-
private trackedPositionsFbo: regl.Framebuffer2D | undefined
|
|
47
|
-
private sampledPointsFbo: regl.Framebuffer2D | undefined
|
|
48
|
-
private trackedPositions: Map<number, [number, number]> | undefined
|
|
49
|
-
private isPositionsUpToDate = false
|
|
50
|
-
private drawCommand: regl.DrawCommand | undefined
|
|
51
|
-
private drawHighlightedCommand: regl.DrawCommand | undefined
|
|
52
|
-
private updatePositionCommand: regl.DrawCommand | undefined
|
|
53
|
-
private dragPointCommand: regl.DrawCommand | undefined
|
|
54
|
-
private findPointsOnAreaSelectionCommand: regl.DrawCommand | undefined
|
|
55
|
-
private findPointsOnPolygonSelectionCommand: regl.DrawCommand | undefined
|
|
56
|
-
private findHoveredPointCommand: regl.DrawCommand | undefined
|
|
57
|
-
private clearHoveredFboCommand: regl.DrawCommand | undefined
|
|
58
|
-
private clearSampledPointsFboCommand: regl.DrawCommand | undefined
|
|
59
|
-
private fillSampledPointsFboCommand: regl.DrawCommand | undefined
|
|
60
|
-
private trackPointsCommand: regl.DrawCommand | undefined
|
|
61
|
-
private trackedIndices: number[] | undefined
|
|
62
|
-
private selectedTexture: regl.Texture2D | undefined
|
|
63
|
-
private greyoutStatusTexture: regl.Texture2D | undefined
|
|
64
|
-
private pinnedStatusTexture: regl.Texture2D | undefined
|
|
65
|
-
private pinnedStatusFbo: regl.Framebuffer2D | undefined
|
|
66
|
-
private sizeTexture: regl.Texture2D | undefined
|
|
67
|
-
private trackedIndicesTexture: regl.Texture2D | undefined
|
|
68
|
-
private polygonPathTexture: regl.Texture2D | undefined
|
|
69
|
-
private polygonPathFbo: regl.Framebuffer2D | undefined
|
|
70
|
-
private polygonPathLength = 0
|
|
71
|
-
private drawPointIndices: regl.Buffer | undefined
|
|
72
|
-
private hoveredPointIndices: regl.Buffer | undefined
|
|
73
|
-
private sampledPointIndices: regl.Buffer | undefined
|
|
74
|
-
|
|
75
|
-
public updatePositions (): void {
|
|
76
|
-
const { reglInstance, store, data, config: { rescalePositions, enableSimulation } } = this
|
|
77
|
-
|
|
78
|
-
const { pointsTextureSize } = store
|
|
79
|
-
if (!pointsTextureSize || !data.pointPositions || data.pointsNumber === undefined) return
|
|
80
|
-
|
|
81
|
-
const initialState = new Float32Array(pointsTextureSize * pointsTextureSize * 4)
|
|
82
|
-
|
|
83
|
-
let shouldRescale = rescalePositions
|
|
84
|
-
// If rescalePositions isn't specified in config and simulation is disabled, default to true
|
|
85
|
-
if (rescalePositions === undefined && !enableSimulation) shouldRescale = true
|
|
86
|
-
// Skip rescaling if `shouldSkipRescale` flag is set (allowing one-time skip of rescaling)
|
|
87
|
-
// Temporary flag is used to skip rescaling when change point positions or adding new points by function `setPointPositions`
|
|
88
|
-
// This flag overrides any other rescaling settings
|
|
89
|
-
if (this.shouldSkipRescale) shouldRescale = false
|
|
90
|
-
|
|
91
|
-
if (shouldRescale) {
|
|
92
|
-
this.rescaleInitialNodePositions()
|
|
93
|
-
} else if (!this.shouldSkipRescale) {
|
|
94
|
-
// Only reset scale functions if not temporarily skipping rescale
|
|
95
|
-
this.scaleX = undefined
|
|
96
|
-
this.scaleY = undefined
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Reset temporary flag
|
|
100
|
-
this.shouldSkipRescale = undefined
|
|
101
|
-
|
|
102
|
-
for (let i = 0; i < data.pointsNumber; ++i) {
|
|
103
|
-
initialState[i * 4 + 0] = data.pointPositions[i * 2 + 0] as number
|
|
104
|
-
initialState[i * 4 + 1] = data.pointPositions[i * 2 + 1] as number
|
|
105
|
-
initialState[i * 4 + 2] = i
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Create position buffer
|
|
109
|
-
if (!this.currentPositionFbo) this.currentPositionFbo = reglInstance.framebuffer()
|
|
110
|
-
this.currentPositionFbo({
|
|
111
|
-
color: reglInstance.texture({
|
|
112
|
-
data: initialState,
|
|
113
|
-
shape: [pointsTextureSize, pointsTextureSize, 4],
|
|
114
|
-
type: 'float',
|
|
115
|
-
}),
|
|
116
|
-
depth: false,
|
|
117
|
-
stencil: false,
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
if (!this.previousPositionFbo) this.previousPositionFbo = reglInstance.framebuffer()
|
|
121
|
-
this.previousPositionFbo({
|
|
122
|
-
color: reglInstance.texture({
|
|
123
|
-
data: initialState,
|
|
124
|
-
shape: [pointsTextureSize, pointsTextureSize, 4],
|
|
125
|
-
type: 'float',
|
|
126
|
-
}),
|
|
127
|
-
depth: false,
|
|
128
|
-
stencil: false,
|
|
129
|
-
})
|
|
130
|
-
|
|
131
|
-
if (this.config.enableSimulation) {
|
|
132
|
-
// Create velocity buffer
|
|
133
|
-
if (!this.velocityFbo) this.velocityFbo = reglInstance.framebuffer()
|
|
134
|
-
this.velocityFbo({
|
|
135
|
-
color: reglInstance.texture({
|
|
136
|
-
data: new Float32Array(pointsTextureSize * pointsTextureSize * 4).fill(0),
|
|
137
|
-
shape: [pointsTextureSize, pointsTextureSize, 4],
|
|
138
|
-
type: 'float',
|
|
139
|
-
}),
|
|
140
|
-
depth: false,
|
|
141
|
-
stencil: false,
|
|
142
|
-
})
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Create selected points buffer
|
|
146
|
-
if (!this.selectedTexture) this.selectedTexture = reglInstance.texture()
|
|
147
|
-
this.selectedTexture({
|
|
148
|
-
data: initialState,
|
|
149
|
-
shape: [pointsTextureSize, pointsTextureSize, 4],
|
|
150
|
-
type: 'float',
|
|
151
|
-
})
|
|
152
|
-
if (!this.selectedFbo) this.selectedFbo = reglInstance.framebuffer()
|
|
153
|
-
this.selectedFbo({
|
|
154
|
-
color: this.selectedTexture,
|
|
155
|
-
depth: false,
|
|
156
|
-
stencil: false,
|
|
157
|
-
})
|
|
158
|
-
|
|
159
|
-
if (!this.hoveredFbo) this.hoveredFbo = reglInstance.framebuffer()
|
|
160
|
-
this.hoveredFbo({
|
|
161
|
-
shape: [2, 2],
|
|
162
|
-
colorType: 'float',
|
|
163
|
-
depth: false,
|
|
164
|
-
stencil: false,
|
|
165
|
-
})
|
|
166
|
-
|
|
167
|
-
if (!this.drawPointIndices) this.drawPointIndices = reglInstance.buffer(0)
|
|
168
|
-
this.drawPointIndices(createIndexesForBuffer(store.pointsTextureSize))
|
|
169
|
-
|
|
170
|
-
if (!this.hoveredPointIndices) this.hoveredPointIndices = reglInstance.buffer(0)
|
|
171
|
-
this.hoveredPointIndices(createIndexesForBuffer(store.pointsTextureSize))
|
|
172
|
-
|
|
173
|
-
if (!this.sampledPointIndices) this.sampledPointIndices = reglInstance.buffer(0)
|
|
174
|
-
this.sampledPointIndices(createIndexesForBuffer(store.pointsTextureSize))
|
|
175
|
-
|
|
176
|
-
this.updateGreyoutStatus()
|
|
177
|
-
this.updatePinnedStatus()
|
|
178
|
-
this.updateSampledPointsGrid()
|
|
179
|
-
|
|
180
|
-
this.trackPointsByIndices()
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
public initPrograms (): void {
|
|
184
|
-
const { reglInstance, config, store, data } = this
|
|
185
|
-
if (config.enableSimulation) {
|
|
186
|
-
if (!this.updatePositionCommand) {
|
|
187
|
-
this.updatePositionCommand = reglInstance({
|
|
188
|
-
frag: updatePositionFrag,
|
|
189
|
-
vert: updateVert,
|
|
190
|
-
framebuffer: () => this.currentPositionFbo as regl.Framebuffer2D,
|
|
191
|
-
primitive: 'triangle strip',
|
|
192
|
-
count: 4,
|
|
193
|
-
attributes: { vertexCoord: createQuadBuffer(reglInstance) },
|
|
194
|
-
uniforms: {
|
|
195
|
-
positionsTexture: () => this.previousPositionFbo,
|
|
196
|
-
velocity: () => this.velocityFbo,
|
|
197
|
-
friction: () => config.simulationFriction,
|
|
198
|
-
spaceSize: () => store.adjustedSpaceSize,
|
|
199
|
-
pinnedStatusTexture: () => this.pinnedStatusFbo,
|
|
200
|
-
},
|
|
201
|
-
})
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
if (!this.dragPointCommand) {
|
|
205
|
-
this.dragPointCommand = reglInstance({
|
|
206
|
-
frag: dragPointFrag,
|
|
207
|
-
vert: updateVert,
|
|
208
|
-
framebuffer: () => this.currentPositionFbo as regl.Framebuffer2D,
|
|
209
|
-
primitive: 'triangle strip',
|
|
210
|
-
count: 4,
|
|
211
|
-
attributes: { vertexCoord: createQuadBuffer(reglInstance) },
|
|
212
|
-
uniforms: {
|
|
213
|
-
positionsTexture: () => this.previousPositionFbo,
|
|
214
|
-
mousePos: () => store.mousePosition,
|
|
215
|
-
index: () => store.hoveredPoint?.index ?? -1,
|
|
216
|
-
},
|
|
217
|
-
})
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
if (!this.drawCommand) {
|
|
221
|
-
this.drawCommand = reglInstance({
|
|
222
|
-
frag: drawPointsFrag,
|
|
223
|
-
vert: drawPointsVert,
|
|
224
|
-
primitive: 'points',
|
|
225
|
-
count: () => data.pointsNumber ?? 0,
|
|
226
|
-
attributes: {
|
|
227
|
-
pointIndices: {
|
|
228
|
-
buffer: this.drawPointIndices,
|
|
229
|
-
size: 2,
|
|
230
|
-
},
|
|
231
|
-
size: {
|
|
232
|
-
buffer: () => this.sizeBuffer,
|
|
233
|
-
size: 1,
|
|
234
|
-
},
|
|
235
|
-
color: {
|
|
236
|
-
buffer: () => this.colorBuffer,
|
|
237
|
-
size: 4,
|
|
238
|
-
},
|
|
239
|
-
shape: {
|
|
240
|
-
buffer: () => this.shapeBuffer,
|
|
241
|
-
size: 1,
|
|
242
|
-
},
|
|
243
|
-
imageIndex: {
|
|
244
|
-
buffer: () => this.imageIndicesBuffer,
|
|
245
|
-
size: 1,
|
|
246
|
-
},
|
|
247
|
-
imageSize: {
|
|
248
|
-
buffer: () => this.imageSizesBuffer,
|
|
249
|
-
size: 1,
|
|
250
|
-
},
|
|
251
|
-
},
|
|
252
|
-
uniforms: {
|
|
253
|
-
positionsTexture: () => this.currentPositionFbo,
|
|
254
|
-
pointGreyoutStatus: () => this.greyoutStatusFbo,
|
|
255
|
-
ratio: () => config.pixelRatio,
|
|
256
|
-
sizeScale: () => config.pointSizeScale,
|
|
257
|
-
pointsTextureSize: () => store.pointsTextureSize,
|
|
258
|
-
transformationMatrix: () => store.transform,
|
|
259
|
-
spaceSize: () => store.adjustedSpaceSize,
|
|
260
|
-
screenSize: () => store.screenSize,
|
|
261
|
-
pointOpacity: () => config.pointOpacity,
|
|
262
|
-
greyoutOpacity: () => config.pointGreyoutOpacity ?? -1,
|
|
263
|
-
greyoutColor: () => store.greyoutPointColor,
|
|
264
|
-
backgroundColor: () => store.backgroundColor,
|
|
265
|
-
isDarkenGreyout: () => store.isDarkenGreyout,
|
|
266
|
-
scalePointsOnZoom: () => config.scalePointsOnZoom,
|
|
267
|
-
maxPointSize: () => store.maxPointSize,
|
|
268
|
-
skipSelected: reglInstance.prop<{ skipSelected: boolean }, 'skipSelected'>('skipSelected'),
|
|
269
|
-
skipUnselected: reglInstance.prop<{ skipUnselected: boolean }, 'skipUnselected'>('skipUnselected'),
|
|
270
|
-
imageAtlasTexture: () => this.imageAtlasTexture,
|
|
271
|
-
imageAtlasCoords: () => this.imageAtlasCoordsTexture,
|
|
272
|
-
hasImages: () => this.imageCount > 0,
|
|
273
|
-
imageCount: () => this.imageCount,
|
|
274
|
-
imageAtlasCoordsTextureSize: () => this.imageAtlasCoordsTextureSize,
|
|
275
|
-
},
|
|
276
|
-
blend: {
|
|
277
|
-
enable: true,
|
|
278
|
-
func: {
|
|
279
|
-
dstRGB: 'one minus src alpha',
|
|
280
|
-
srcRGB: 'src alpha',
|
|
281
|
-
dstAlpha: 'one minus src alpha',
|
|
282
|
-
srcAlpha: 'one',
|
|
283
|
-
},
|
|
284
|
-
equation: {
|
|
285
|
-
rgb: 'add',
|
|
286
|
-
alpha: 'add',
|
|
287
|
-
},
|
|
288
|
-
},
|
|
289
|
-
depth: {
|
|
290
|
-
enable: false,
|
|
291
|
-
mask: false,
|
|
292
|
-
},
|
|
293
|
-
})
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
if (!this.findPointsOnAreaSelectionCommand) {
|
|
297
|
-
this.findPointsOnAreaSelectionCommand = reglInstance({
|
|
298
|
-
frag: findPointsOnAreaSelectionFrag,
|
|
299
|
-
vert: updateVert,
|
|
300
|
-
framebuffer: () => this.selectedFbo as regl.Framebuffer2D,
|
|
301
|
-
primitive: 'triangle strip',
|
|
302
|
-
count: 4,
|
|
303
|
-
attributes: {
|
|
304
|
-
vertexCoord: createQuadBuffer(reglInstance),
|
|
305
|
-
},
|
|
306
|
-
uniforms: {
|
|
307
|
-
positionsTexture: () => this.currentPositionFbo,
|
|
308
|
-
pointSize: () => this.sizeFbo,
|
|
309
|
-
spaceSize: () => store.adjustedSpaceSize,
|
|
310
|
-
screenSize: () => store.screenSize,
|
|
311
|
-
sizeScale: () => config.pointSizeScale,
|
|
312
|
-
transformationMatrix: () => store.transform,
|
|
313
|
-
ratio: () => config.pixelRatio,
|
|
314
|
-
selection0: () => store.selectedArea[0],
|
|
315
|
-
selection1: () => store.selectedArea[1],
|
|
316
|
-
scalePointsOnZoom: () => config.scalePointsOnZoom,
|
|
317
|
-
maxPointSize: () => store.maxPointSize,
|
|
318
|
-
},
|
|
319
|
-
})
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
if (!this.findPointsOnPolygonSelectionCommand) {
|
|
323
|
-
this.findPointsOnPolygonSelectionCommand = reglInstance({
|
|
324
|
-
frag: findPointsOnPolygonSelectionFrag,
|
|
325
|
-
vert: updateVert,
|
|
326
|
-
framebuffer: () => this.selectedFbo as regl.Framebuffer2D,
|
|
327
|
-
primitive: 'triangle strip',
|
|
328
|
-
count: 4,
|
|
329
|
-
attributes: {
|
|
330
|
-
vertexCoord: createQuadBuffer(reglInstance),
|
|
331
|
-
},
|
|
332
|
-
uniforms: {
|
|
333
|
-
positionsTexture: () => this.currentPositionFbo,
|
|
334
|
-
spaceSize: () => store.adjustedSpaceSize,
|
|
335
|
-
screenSize: () => store.screenSize,
|
|
336
|
-
transformationMatrix: () => store.transform,
|
|
337
|
-
polygonPathTexture: () => this.polygonPathTexture,
|
|
338
|
-
polygonPathLength: () => this.polygonPathLength,
|
|
339
|
-
},
|
|
340
|
-
})
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
if (!this.clearHoveredFboCommand) {
|
|
344
|
-
this.clearHoveredFboCommand = reglInstance({
|
|
345
|
-
frag: clearFrag,
|
|
346
|
-
vert: updateVert,
|
|
347
|
-
framebuffer: this.hoveredFbo as regl.Framebuffer2D,
|
|
348
|
-
primitive: 'triangle strip',
|
|
349
|
-
count: 4,
|
|
350
|
-
attributes: { vertexCoord: createQuadBuffer(reglInstance) },
|
|
351
|
-
})
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
if (!this.findHoveredPointCommand) {
|
|
355
|
-
this.findHoveredPointCommand = reglInstance({
|
|
356
|
-
frag: findHoveredPointFrag,
|
|
357
|
-
vert: findHoveredPointVert,
|
|
358
|
-
primitive: 'points',
|
|
359
|
-
count: () => data.pointsNumber ?? 0,
|
|
360
|
-
framebuffer: () => this.hoveredFbo as regl.Framebuffer2D,
|
|
361
|
-
attributes: {
|
|
362
|
-
pointIndices: {
|
|
363
|
-
buffer: this.hoveredPointIndices,
|
|
364
|
-
size: 2,
|
|
365
|
-
},
|
|
366
|
-
size: {
|
|
367
|
-
buffer: () => this.sizeBuffer,
|
|
368
|
-
size: 1,
|
|
369
|
-
},
|
|
370
|
-
},
|
|
371
|
-
uniforms: {
|
|
372
|
-
positionsTexture: () => this.currentPositionFbo,
|
|
373
|
-
ratio: () => config.pixelRatio,
|
|
374
|
-
sizeScale: () => config.pointSizeScale,
|
|
375
|
-
pointsTextureSize: () => store.pointsTextureSize,
|
|
376
|
-
transformationMatrix: () => store.transform,
|
|
377
|
-
spaceSize: () => store.adjustedSpaceSize,
|
|
378
|
-
screenSize: () => store.screenSize,
|
|
379
|
-
scalePointsOnZoom: () => config.scalePointsOnZoom,
|
|
380
|
-
mousePosition: () => store.screenMousePosition,
|
|
381
|
-
maxPointSize: () => store.maxPointSize,
|
|
382
|
-
},
|
|
383
|
-
depth: {
|
|
384
|
-
enable: false,
|
|
385
|
-
mask: false,
|
|
386
|
-
},
|
|
387
|
-
})
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
if (!this.clearSampledPointsFboCommand) {
|
|
391
|
-
this.clearSampledPointsFboCommand = reglInstance({
|
|
392
|
-
frag: clearFrag,
|
|
393
|
-
vert: updateVert,
|
|
394
|
-
framebuffer: () => this.sampledPointsFbo as regl.Framebuffer2D,
|
|
395
|
-
primitive: 'triangle strip',
|
|
396
|
-
count: 4,
|
|
397
|
-
attributes: { vertexCoord: createQuadBuffer(reglInstance) },
|
|
398
|
-
})
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
if (!this.fillSampledPointsFboCommand) {
|
|
402
|
-
this.fillSampledPointsFboCommand = reglInstance({
|
|
403
|
-
frag: fillGridWithSampledPointsFrag,
|
|
404
|
-
vert: fillGridWithSampledPointsVert,
|
|
405
|
-
primitive: 'points',
|
|
406
|
-
count: () => data.pointsNumber ?? 0,
|
|
407
|
-
framebuffer: () => this.sampledPointsFbo as regl.Framebuffer2D,
|
|
408
|
-
attributes: {
|
|
409
|
-
pointIndices: {
|
|
410
|
-
buffer: this.sampledPointIndices,
|
|
411
|
-
size: 2,
|
|
412
|
-
},
|
|
413
|
-
},
|
|
414
|
-
uniforms: {
|
|
415
|
-
positionsTexture: () => this.currentPositionFbo,
|
|
416
|
-
pointsTextureSize: () => store.pointsTextureSize,
|
|
417
|
-
transformationMatrix: () => store.transform,
|
|
418
|
-
spaceSize: () => store.adjustedSpaceSize,
|
|
419
|
-
screenSize: () => store.screenSize,
|
|
420
|
-
},
|
|
421
|
-
depth: {
|
|
422
|
-
enable: false,
|
|
423
|
-
mask: false,
|
|
424
|
-
},
|
|
425
|
-
})
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
if (!this.drawHighlightedCommand) {
|
|
429
|
-
this.drawHighlightedCommand = reglInstance({
|
|
430
|
-
frag: drawHighlightedFrag,
|
|
431
|
-
vert: drawHighlightedVert,
|
|
432
|
-
attributes: { vertexCoord: createQuadBuffer(reglInstance) },
|
|
433
|
-
primitive: 'triangle strip',
|
|
434
|
-
count: 4,
|
|
435
|
-
uniforms: {
|
|
436
|
-
color: reglInstance.prop<{ color: number[] }, 'color'>('color'),
|
|
437
|
-
width: reglInstance.prop<{ width: number }, 'width'>('width'),
|
|
438
|
-
pointIndex: reglInstance.prop<{ pointIndex: number }, 'pointIndex'>('pointIndex'),
|
|
439
|
-
size: reglInstance.prop<{ size: number }, 'size'>('size'),
|
|
440
|
-
positionsTexture: () => this.currentPositionFbo,
|
|
441
|
-
sizeScale: () => config.pointSizeScale,
|
|
442
|
-
pointsTextureSize: () => store.pointsTextureSize,
|
|
443
|
-
transformationMatrix: () => store.transform,
|
|
444
|
-
spaceSize: () => store.adjustedSpaceSize,
|
|
445
|
-
screenSize: () => store.screenSize,
|
|
446
|
-
scalePointsOnZoom: () => config.scalePointsOnZoom,
|
|
447
|
-
maxPointSize: () => store.maxPointSize,
|
|
448
|
-
pointGreyoutStatusTexture: () => this.greyoutStatusFbo,
|
|
449
|
-
universalPointOpacity: () => config.pointOpacity,
|
|
450
|
-
greyoutOpacity: () => config.pointGreyoutOpacity ?? -1,
|
|
451
|
-
isDarkenGreyout: () => store.isDarkenGreyout,
|
|
452
|
-
backgroundColor: () => store.backgroundColor,
|
|
453
|
-
greyoutColor: () => store.greyoutPointColor,
|
|
454
|
-
},
|
|
455
|
-
blend: {
|
|
456
|
-
enable: true,
|
|
457
|
-
func: {
|
|
458
|
-
dstRGB: 'one minus src alpha',
|
|
459
|
-
srcRGB: 'src alpha',
|
|
460
|
-
dstAlpha: 'one minus src alpha',
|
|
461
|
-
srcAlpha: 'one',
|
|
462
|
-
},
|
|
463
|
-
equation: {
|
|
464
|
-
rgb: 'add',
|
|
465
|
-
alpha: 'add',
|
|
466
|
-
},
|
|
467
|
-
},
|
|
468
|
-
depth: {
|
|
469
|
-
enable: false,
|
|
470
|
-
mask: false,
|
|
471
|
-
},
|
|
472
|
-
})
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
if (!this.trackPointsCommand) {
|
|
476
|
-
this.trackPointsCommand = reglInstance({
|
|
477
|
-
frag: trackPositionsFrag,
|
|
478
|
-
vert: updateVert,
|
|
479
|
-
framebuffer: () => this.trackedPositionsFbo as regl.Framebuffer2D,
|
|
480
|
-
primitive: 'triangle strip',
|
|
481
|
-
count: 4,
|
|
482
|
-
attributes: { vertexCoord: createQuadBuffer(reglInstance) },
|
|
483
|
-
uniforms: {
|
|
484
|
-
positionsTexture: () => this.currentPositionFbo,
|
|
485
|
-
trackedIndices: () => this.trackedIndicesFbo,
|
|
486
|
-
pointsTextureSize: () => store.pointsTextureSize,
|
|
487
|
-
},
|
|
488
|
-
})
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
public updateColor (): void {
|
|
493
|
-
const { reglInstance, store: { pointsTextureSize }, data } = this
|
|
494
|
-
if (!pointsTextureSize) return
|
|
495
|
-
if (!this.colorBuffer) this.colorBuffer = reglInstance.buffer(0)
|
|
496
|
-
this.colorBuffer(data.pointColors as Float32Array)
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
public updateGreyoutStatus (): void {
|
|
500
|
-
const { reglInstance, store: { selectedIndices, pointsTextureSize } } = this
|
|
501
|
-
if (!pointsTextureSize) return
|
|
502
|
-
|
|
503
|
-
// Greyout status: 0 - false, highlighted or normal point; 1 - true, greyout point
|
|
504
|
-
const initialState = new Float32Array(pointsTextureSize * pointsTextureSize * 4)
|
|
505
|
-
.fill(selectedIndices ? 1 : 0)
|
|
506
|
-
|
|
507
|
-
if (selectedIndices) {
|
|
508
|
-
for (const selectedIndex of selectedIndices) {
|
|
509
|
-
initialState[selectedIndex * 4] = 0
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
if (!this.greyoutStatusTexture) this.greyoutStatusTexture = reglInstance.texture()
|
|
513
|
-
this.greyoutStatusTexture({
|
|
514
|
-
data: initialState,
|
|
515
|
-
width: pointsTextureSize,
|
|
516
|
-
height: pointsTextureSize,
|
|
517
|
-
type: 'float',
|
|
518
|
-
})
|
|
519
|
-
if (!this.greyoutStatusFbo) this.greyoutStatusFbo = reglInstance.framebuffer()
|
|
520
|
-
this.greyoutStatusFbo({
|
|
521
|
-
color: this.greyoutStatusTexture,
|
|
522
|
-
depth: false,
|
|
523
|
-
stencil: false,
|
|
524
|
-
})
|
|
525
|
-
}
|
|
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
|
-
|
|
557
|
-
public updateSize (): void {
|
|
558
|
-
const { reglInstance, store: { pointsTextureSize }, data } = this
|
|
559
|
-
if (!pointsTextureSize || data.pointsNumber === undefined || data.pointSizes === undefined) return
|
|
560
|
-
if (!this.sizeBuffer) this.sizeBuffer = reglInstance.buffer(0)
|
|
561
|
-
this.sizeBuffer(data.pointSizes)
|
|
562
|
-
|
|
563
|
-
const initialState = new Float32Array(pointsTextureSize * pointsTextureSize * 4)
|
|
564
|
-
for (let i = 0; i < data.pointsNumber; i++) {
|
|
565
|
-
initialState[i * 4] = data.pointSizes[i] as number
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
if (!this.sizeTexture) this.sizeTexture = reglInstance.texture()
|
|
569
|
-
this.sizeTexture({
|
|
570
|
-
data: initialState,
|
|
571
|
-
width: pointsTextureSize,
|
|
572
|
-
height: pointsTextureSize,
|
|
573
|
-
type: 'float',
|
|
574
|
-
})
|
|
575
|
-
|
|
576
|
-
if (!this.sizeFbo) this.sizeFbo = reglInstance.framebuffer()
|
|
577
|
-
this.sizeFbo({
|
|
578
|
-
color: this.sizeTexture,
|
|
579
|
-
depth: false,
|
|
580
|
-
stencil: false,
|
|
581
|
-
})
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
public updateShape (): void {
|
|
585
|
-
const { reglInstance, data } = this
|
|
586
|
-
if (data.pointsNumber === undefined || data.pointShapes === undefined) return
|
|
587
|
-
if (!this.shapeBuffer) this.shapeBuffer = reglInstance.buffer(0)
|
|
588
|
-
this.shapeBuffer(data.pointShapes)
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
public updateImageIndices (): void {
|
|
592
|
-
const { reglInstance, data } = this
|
|
593
|
-
if (data.pointsNumber === undefined || data.pointImageIndices === undefined) return
|
|
594
|
-
if (!this.imageIndicesBuffer) this.imageIndicesBuffer = reglInstance.buffer(0)
|
|
595
|
-
this.imageIndicesBuffer(data.pointImageIndices)
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
public updateImageSizes (): void {
|
|
599
|
-
const { reglInstance, data } = this
|
|
600
|
-
if (data.pointsNumber === undefined || data.pointImageSizes === undefined) return
|
|
601
|
-
if (!this.imageSizesBuffer) this.imageSizesBuffer = reglInstance.buffer(0)
|
|
602
|
-
this.imageSizesBuffer(data.pointImageSizes)
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
public createAtlas (): void {
|
|
606
|
-
const { reglInstance, data, store } = this
|
|
607
|
-
if (!this.imageAtlasTexture) this.imageAtlasTexture = reglInstance.texture()
|
|
608
|
-
if (!this.imageAtlasCoordsTexture) this.imageAtlasCoordsTexture = reglInstance.texture()
|
|
609
|
-
|
|
610
|
-
if (!data.inputImageData?.length) {
|
|
611
|
-
this.imageCount = 0
|
|
612
|
-
this.imageAtlasCoordsTextureSize = 0
|
|
613
|
-
return
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
const atlasResult = createAtlasDataFromImageData(data.inputImageData, store.webglMaxTextureSize)
|
|
617
|
-
if (!atlasResult) {
|
|
618
|
-
console.warn('Failed to create atlas from image data')
|
|
619
|
-
return
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
this.imageCount = data.inputImageData.length
|
|
623
|
-
const { atlasData, atlasSize, atlasCoords, atlasCoordsSize } = atlasResult
|
|
624
|
-
this.imageAtlasCoordsTextureSize = atlasCoordsSize
|
|
625
|
-
|
|
626
|
-
this.imageAtlasTexture({
|
|
627
|
-
data: atlasData,
|
|
628
|
-
shape: [atlasSize, atlasSize, 4],
|
|
629
|
-
type: 'uint8',
|
|
630
|
-
})
|
|
631
|
-
|
|
632
|
-
this.imageAtlasCoordsTexture({
|
|
633
|
-
data: atlasCoords,
|
|
634
|
-
shape: [atlasCoordsSize, atlasCoordsSize, 4],
|
|
635
|
-
type: 'float',
|
|
636
|
-
})
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
public updateSampledPointsGrid (): void {
|
|
640
|
-
const { store: { screenSize }, config: { pointSamplingDistance }, reglInstance } = this
|
|
641
|
-
let dist = pointSamplingDistance ?? Math.min(...screenSize) / 2
|
|
642
|
-
if (dist === 0) dist = defaultConfigValues.pointSamplingDistance
|
|
643
|
-
const w = Math.ceil(screenSize[0] / dist)
|
|
644
|
-
const h = Math.ceil(screenSize[1] / dist)
|
|
645
|
-
if (!this.sampledPointsFbo) this.sampledPointsFbo = reglInstance.framebuffer()
|
|
646
|
-
this.sampledPointsFbo({
|
|
647
|
-
shape: [w, h],
|
|
648
|
-
depth: false,
|
|
649
|
-
stencil: false,
|
|
650
|
-
colorType: 'float',
|
|
651
|
-
})
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
public trackPoints (): void {
|
|
655
|
-
if (!this.trackedIndices?.length) return
|
|
656
|
-
this.trackPointsCommand?.()
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
public draw (): void {
|
|
660
|
-
const { config: { renderHoveredPointRing, pointSize }, store, data } = this
|
|
661
|
-
if (!this.colorBuffer) this.updateColor()
|
|
662
|
-
if (!this.sizeBuffer) this.updateSize()
|
|
663
|
-
if (!this.shapeBuffer) this.updateShape()
|
|
664
|
-
if (!this.imageIndicesBuffer) this.updateImageIndices()
|
|
665
|
-
if (!this.imageSizesBuffer) this.updateImageSizes()
|
|
666
|
-
if (!this.imageAtlasCoordsTexture || !this.imageAtlasTexture) this.createAtlas()
|
|
667
|
-
|
|
668
|
-
// Render in layers: unselected points first (behind), then selected points (in front)
|
|
669
|
-
if (store.selectedIndices && store.selectedIndices.length > 0) {
|
|
670
|
-
// First draw unselected points (they will appear behind)
|
|
671
|
-
this.drawCommand?.({ skipSelected: true, skipUnselected: false })
|
|
672
|
-
// Then draw selected points (they will appear in front)
|
|
673
|
-
this.drawCommand?.({ skipSelected: false, skipUnselected: true })
|
|
674
|
-
} else {
|
|
675
|
-
// If no selection, draw all points
|
|
676
|
-
this.drawCommand?.({ skipSelected: false, skipUnselected: false })
|
|
677
|
-
}
|
|
678
|
-
if ((renderHoveredPointRing) && store.hoveredPoint) {
|
|
679
|
-
this.drawHighlightedCommand?.({
|
|
680
|
-
width: 0.85,
|
|
681
|
-
color: store.hoveredPointRingColor,
|
|
682
|
-
pointIndex: store.hoveredPoint.index,
|
|
683
|
-
size: data.pointSizes?.[store.hoveredPoint.index] ?? pointSize,
|
|
684
|
-
})
|
|
685
|
-
}
|
|
686
|
-
if (store.focusedPoint) {
|
|
687
|
-
this.drawHighlightedCommand?.({
|
|
688
|
-
width: 0.75,
|
|
689
|
-
color: store.focusedPointRingColor,
|
|
690
|
-
pointIndex: store.focusedPoint.index,
|
|
691
|
-
size: data.pointSizes?.[store.focusedPoint.index] ?? pointSize,
|
|
692
|
-
})
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
public updatePosition (): void {
|
|
697
|
-
this.updatePositionCommand?.()
|
|
698
|
-
this.swapFbo()
|
|
699
|
-
// Invalidate tracked positions cache since positions have changed
|
|
700
|
-
this.isPositionsUpToDate = false
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
public drag (): void {
|
|
704
|
-
this.dragPointCommand?.()
|
|
705
|
-
this.swapFbo()
|
|
706
|
-
// Invalidate tracked positions cache since positions have changed
|
|
707
|
-
this.isPositionsUpToDate = false
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
public findPointsOnAreaSelection (): void {
|
|
711
|
-
this.findPointsOnAreaSelectionCommand?.()
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
public findPointsOnPolygonSelection (): void {
|
|
715
|
-
this.findPointsOnPolygonSelectionCommand?.()
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
public updatePolygonPath (polygonPath: [number, number][]): void {
|
|
719
|
-
const { reglInstance } = this
|
|
720
|
-
this.polygonPathLength = polygonPath.length
|
|
721
|
-
|
|
722
|
-
if (polygonPath.length === 0) {
|
|
723
|
-
this.polygonPathTexture = undefined
|
|
724
|
-
this.polygonPathFbo = undefined
|
|
725
|
-
return
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
// Calculate texture size (square texture)
|
|
729
|
-
const textureSize = Math.ceil(Math.sqrt(polygonPath.length))
|
|
730
|
-
const textureData = new Float32Array(textureSize * textureSize * 4)
|
|
731
|
-
|
|
732
|
-
// Fill texture with polygon path points
|
|
733
|
-
for (const [i, point] of polygonPath.entries()) {
|
|
734
|
-
const [x, y] = point
|
|
735
|
-
textureData[i * 4] = x
|
|
736
|
-
textureData[i * 4 + 1] = y
|
|
737
|
-
textureData[i * 4 + 2] = 0 // unused
|
|
738
|
-
textureData[i * 4 + 3] = 0 // unused
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
if (!this.polygonPathTexture) this.polygonPathTexture = reglInstance.texture()
|
|
742
|
-
this.polygonPathTexture({
|
|
743
|
-
data: textureData,
|
|
744
|
-
width: textureSize,
|
|
745
|
-
height: textureSize,
|
|
746
|
-
type: 'float',
|
|
747
|
-
})
|
|
748
|
-
|
|
749
|
-
if (!this.polygonPathFbo) this.polygonPathFbo = reglInstance.framebuffer()
|
|
750
|
-
this.polygonPathFbo({
|
|
751
|
-
color: this.polygonPathTexture,
|
|
752
|
-
depth: false,
|
|
753
|
-
stencil: false,
|
|
754
|
-
})
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
public findHoveredPoint (): void {
|
|
758
|
-
this.clearHoveredFboCommand?.()
|
|
759
|
-
this.findHoveredPointCommand?.()
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
public trackPointsByIndices (indices?: number[] | undefined): void {
|
|
763
|
-
const { store: { pointsTextureSize }, reglInstance } = this
|
|
764
|
-
this.trackedIndices = indices
|
|
765
|
-
|
|
766
|
-
// Clear cache when changing tracked indices
|
|
767
|
-
this.trackedPositions = undefined
|
|
768
|
-
this.isPositionsUpToDate = false
|
|
769
|
-
|
|
770
|
-
if (!indices?.length || !pointsTextureSize) return
|
|
771
|
-
const textureSize = Math.ceil(Math.sqrt(indices.length))
|
|
772
|
-
|
|
773
|
-
const initialState = new Float32Array(textureSize * textureSize * 4).fill(-1)
|
|
774
|
-
for (const [i, sortedIndex] of indices.entries()) {
|
|
775
|
-
if (sortedIndex !== undefined) {
|
|
776
|
-
initialState[i * 4] = sortedIndex % pointsTextureSize
|
|
777
|
-
initialState[i * 4 + 1] = Math.floor(sortedIndex / pointsTextureSize)
|
|
778
|
-
initialState[i * 4 + 2] = 0
|
|
779
|
-
initialState[i * 4 + 3] = 0
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
if (!this.trackedIndicesTexture) this.trackedIndicesTexture = reglInstance.texture()
|
|
783
|
-
this.trackedIndicesTexture({
|
|
784
|
-
data: initialState,
|
|
785
|
-
width: textureSize,
|
|
786
|
-
height: textureSize,
|
|
787
|
-
type: 'float',
|
|
788
|
-
})
|
|
789
|
-
if (!this.trackedIndicesFbo) this.trackedIndicesFbo = reglInstance.framebuffer()
|
|
790
|
-
this.trackedIndicesFbo({
|
|
791
|
-
color: this.trackedIndicesTexture,
|
|
792
|
-
depth: false,
|
|
793
|
-
stencil: false,
|
|
794
|
-
})
|
|
795
|
-
|
|
796
|
-
if (!this.trackedPositionsFbo) this.trackedPositionsFbo = reglInstance.framebuffer()
|
|
797
|
-
this.trackedPositionsFbo({
|
|
798
|
-
shape: [textureSize, textureSize],
|
|
799
|
-
depth: false,
|
|
800
|
-
stencil: false,
|
|
801
|
-
colorType: 'float',
|
|
802
|
-
})
|
|
803
|
-
|
|
804
|
-
this.trackPoints()
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
/**
|
|
808
|
-
* Get current X and Y coordinates of the tracked points.
|
|
809
|
-
*
|
|
810
|
-
* When the simulation is disabled or stopped, this method returns a cached
|
|
811
|
-
* result to avoid expensive GPU-to-CPU memory transfers (`readPixels`).
|
|
812
|
-
*
|
|
813
|
-
* @returns A ReadonlyMap where keys are point indices and values are [x, y] coordinates.
|
|
814
|
-
*/
|
|
815
|
-
public getTrackedPositionsMap (): ReadonlyMap<number, [number, number]> {
|
|
816
|
-
if (!this.trackedIndices) return new Map()
|
|
817
|
-
|
|
818
|
-
const { config: { enableSimulation }, store: { isSimulationRunning } } = this
|
|
819
|
-
|
|
820
|
-
// Use cached positions when simulation is inactive and cache is valid
|
|
821
|
-
if ((!enableSimulation || !isSimulationRunning) &&
|
|
822
|
-
this.isPositionsUpToDate &&
|
|
823
|
-
this.trackedPositions) {
|
|
824
|
-
return this.trackedPositions
|
|
825
|
-
}
|
|
826
|
-
|
|
827
|
-
const pixels = readPixels(this.reglInstance, this.trackedPositionsFbo as regl.Framebuffer2D)
|
|
828
|
-
|
|
829
|
-
const tracked = new Map<number, [number, number]>()
|
|
830
|
-
for (let i = 0; i < pixels.length / 4; i += 1) {
|
|
831
|
-
const x = pixels[i * 4]
|
|
832
|
-
const y = pixels[i * 4 + 1]
|
|
833
|
-
const index = this.trackedIndices[i]
|
|
834
|
-
if (x !== undefined && y !== undefined && index !== undefined) {
|
|
835
|
-
tracked.set(index, [x, y])
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
// If simulation is inactive, cache the result for next time
|
|
840
|
-
if (!enableSimulation || !isSimulationRunning) {
|
|
841
|
-
this.trackedPositions = tracked
|
|
842
|
-
this.isPositionsUpToDate = true
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
return tracked
|
|
846
|
-
}
|
|
847
|
-
|
|
848
|
-
public getSampledPointPositionsMap (): Map<number, [number, number]> {
|
|
849
|
-
const positions = new Map<number, [number, number]>()
|
|
850
|
-
if (!this.sampledPointsFbo) return positions
|
|
851
|
-
this.clearSampledPointsFboCommand?.()
|
|
852
|
-
this.fillSampledPointsFboCommand?.()
|
|
853
|
-
const pixels = readPixels(this.reglInstance, this.sampledPointsFbo as regl.Framebuffer2D)
|
|
854
|
-
for (let i = 0; i < pixels.length / 4; i++) {
|
|
855
|
-
const index = pixels[i * 4]
|
|
856
|
-
const isNotEmpty = !!pixels[i * 4 + 1]
|
|
857
|
-
const x = pixels[i * 4 + 2]
|
|
858
|
-
const y = pixels[i * 4 + 3]
|
|
859
|
-
|
|
860
|
-
if (isNotEmpty && index !== undefined && x !== undefined && y !== undefined) {
|
|
861
|
-
positions.set(index, [x, y])
|
|
862
|
-
}
|
|
863
|
-
}
|
|
864
|
-
return positions
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
public getSampledPoints (): { indices: number[]; positions: number[] } {
|
|
868
|
-
const indices: number[] = []
|
|
869
|
-
const positions: number[] = []
|
|
870
|
-
if (!this.sampledPointsFbo) return { indices, positions }
|
|
871
|
-
|
|
872
|
-
this.clearSampledPointsFboCommand?.()
|
|
873
|
-
this.fillSampledPointsFboCommand?.()
|
|
874
|
-
const pixels = readPixels(this.reglInstance, this.sampledPointsFbo as regl.Framebuffer2D)
|
|
875
|
-
|
|
876
|
-
for (let i = 0; i < pixels.length / 4; i++) {
|
|
877
|
-
const index = pixels[i * 4]
|
|
878
|
-
const isNotEmpty = !!pixels[i * 4 + 1]
|
|
879
|
-
const x = pixels[i * 4 + 2]
|
|
880
|
-
const y = pixels[i * 4 + 3]
|
|
881
|
-
|
|
882
|
-
if (isNotEmpty && index !== undefined && x !== undefined && y !== undefined) {
|
|
883
|
-
indices.push(index)
|
|
884
|
-
positions.push(x, y)
|
|
885
|
-
}
|
|
886
|
-
}
|
|
887
|
-
|
|
888
|
-
return { indices, positions }
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
public getTrackedPositionsArray (): number[] {
|
|
892
|
-
const positions: number[] = []
|
|
893
|
-
if (!this.trackedIndices) return positions
|
|
894
|
-
positions.length = this.trackedIndices.length * 2
|
|
895
|
-
const pixels = readPixels(this.reglInstance, this.trackedPositionsFbo as regl.Framebuffer2D)
|
|
896
|
-
for (let i = 0; i < pixels.length / 4; i += 1) {
|
|
897
|
-
const x = pixels[i * 4]
|
|
898
|
-
const y = pixels[i * 4 + 1]
|
|
899
|
-
const index = this.trackedIndices[i]
|
|
900
|
-
if (x !== undefined && y !== undefined && index !== undefined) {
|
|
901
|
-
positions[i * 2] = x
|
|
902
|
-
positions[i * 2 + 1] = y
|
|
903
|
-
}
|
|
904
|
-
}
|
|
905
|
-
return positions
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
private swapFbo (): void {
|
|
909
|
-
const temp = this.previousPositionFbo
|
|
910
|
-
this.previousPositionFbo = this.currentPositionFbo
|
|
911
|
-
this.currentPositionFbo = temp
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
private rescaleInitialNodePositions (): void {
|
|
915
|
-
const { config: { spaceSize } } = this
|
|
916
|
-
if (!this.data.pointPositions || !spaceSize) return
|
|
917
|
-
|
|
918
|
-
const points = this.data.pointPositions
|
|
919
|
-
const pointsNumber = points.length / 2
|
|
920
|
-
let minX = Infinity
|
|
921
|
-
let maxX = -Infinity
|
|
922
|
-
let minY = Infinity
|
|
923
|
-
let maxY = -Infinity
|
|
924
|
-
for (let i = 0; i < points.length; i += 2) {
|
|
925
|
-
const x = points[i] as number
|
|
926
|
-
const y = points[i + 1] as number
|
|
927
|
-
minX = Math.min(minX, x)
|
|
928
|
-
maxX = Math.max(maxX, x)
|
|
929
|
-
minY = Math.min(minY, y)
|
|
930
|
-
maxY = Math.max(maxY, y)
|
|
931
|
-
}
|
|
932
|
-
const w = maxX - minX
|
|
933
|
-
const h = maxY - minY
|
|
934
|
-
const range = Math.max(w, h)
|
|
935
|
-
|
|
936
|
-
// Do not rescale if the range is greater than the space size (no need to)
|
|
937
|
-
if (range > spaceSize) {
|
|
938
|
-
this.scaleX = undefined
|
|
939
|
-
this.scaleY = undefined
|
|
940
|
-
return
|
|
941
|
-
}
|
|
942
|
-
|
|
943
|
-
// Density threshold - points per pixel ratio (0.001 = 0.1%)
|
|
944
|
-
const densityThreshold = spaceSize * spaceSize * 0.001
|
|
945
|
-
// Calculate effective space size based on point density
|
|
946
|
-
const effectiveSpaceSize = pointsNumber > densityThreshold
|
|
947
|
-
// For dense datasets: scale up based on point count, minimum 120% of space
|
|
948
|
-
? spaceSize * Math.max(1.2, Math.sqrt(pointsNumber) / spaceSize)
|
|
949
|
-
// For sparse datasets: use 10% of space to cluster points closer
|
|
950
|
-
: spaceSize * 0.1
|
|
951
|
-
|
|
952
|
-
// Calculate uniform scale factor to fit data within effective space
|
|
953
|
-
const scaleFactor = effectiveSpaceSize / range
|
|
954
|
-
// Center the data horizontally by adding padding on x-axis
|
|
955
|
-
const offsetX = ((range - w) / 2) * scaleFactor
|
|
956
|
-
// Center the data vertically by adding padding on y-axis
|
|
957
|
-
const offsetY = ((range - h) / 2) * scaleFactor
|
|
958
|
-
|
|
959
|
-
this.scaleX = (x: number): number => (x - minX) * scaleFactor + offsetX
|
|
960
|
-
this.scaleY = (y: number): number => (y - minY) * scaleFactor + offsetY
|
|
961
|
-
|
|
962
|
-
// Apply scaling to point positions
|
|
963
|
-
for (let i = 0; i < pointsNumber; i++) {
|
|
964
|
-
this.data.pointPositions[i * 2] = this.scaleX(points[i * 2] as number)
|
|
965
|
-
this.data.pointPositions[i * 2 + 1] = this.scaleY(points[i * 2 + 1] as number)
|
|
966
|
-
}
|
|
967
|
-
}
|
|
968
|
-
}
|