@cosmos.gl/graph 2.2.0 → 2.2.1
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/index.d.ts +23 -7
- package/dist/index.js +50 -30
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +29 -29
- package/dist/index.min.js.map +1 -1
- package/dist/modules/Points/index.d.ts +6 -6
- package/dist/stories/clusters/{lasso-selection → polygon-selection}/index.d.ts +1 -1
- package/dist/stories/clusters/{lasso-selection/lasso.d.ts → polygon-selection/polygon.d.ts} +5 -5
- package/dist/stories/clusters.stories.d.ts +1 -1
- package/package.json +1 -1
- package/src/index.ts +41 -19
- package/src/modules/Points/{find-points-on-lasso-selection.frag → find-points-on-polygon-selection.frag} +8 -8
- package/src/modules/Points/index.ts +25 -25
- package/src/stories/3. api-reference.mdx +27 -9
- package/src/stories/beginners/basic-set-up/index.ts +1 -1
- package/src/stories/clusters/{lasso-selection → polygon-selection}/index.ts +11 -11
- package/src/stories/clusters/{lasso-selection/lasso.ts → polygon-selection/polygon.ts} +16 -16
- package/src/stories/clusters/{lasso-selection → polygon-selection}/style.css +1 -1
- package/src/stories/clusters.stories.ts +9 -9
|
@@ -21,7 +21,7 @@ export declare class Points extends CoreModule {
|
|
|
21
21
|
private updatePositionCommand;
|
|
22
22
|
private dragPointCommand;
|
|
23
23
|
private findPointsOnAreaSelectionCommand;
|
|
24
|
-
private
|
|
24
|
+
private findPointsOnPolygonSelectionCommand;
|
|
25
25
|
private findHoveredPointCommand;
|
|
26
26
|
private clearHoveredFboCommand;
|
|
27
27
|
private clearSampledPointsFboCommand;
|
|
@@ -32,9 +32,9 @@ export declare class Points extends CoreModule {
|
|
|
32
32
|
private greyoutStatusTexture;
|
|
33
33
|
private sizeTexture;
|
|
34
34
|
private trackedIndicesTexture;
|
|
35
|
-
private
|
|
36
|
-
private
|
|
37
|
-
private
|
|
35
|
+
private polygonPathTexture;
|
|
36
|
+
private polygonPathFbo;
|
|
37
|
+
private polygonPathLength;
|
|
38
38
|
private drawPointIndices;
|
|
39
39
|
private hoveredPointIndices;
|
|
40
40
|
private sampledPointIndices;
|
|
@@ -49,8 +49,8 @@ export declare class Points extends CoreModule {
|
|
|
49
49
|
updatePosition(): void;
|
|
50
50
|
drag(): void;
|
|
51
51
|
findPointsOnAreaSelection(): void;
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
findPointsOnPolygonSelection(): void;
|
|
53
|
+
updatePolygonPath(polygonPath: [number, number][]): void;
|
|
54
54
|
findHoveredPoint(): void;
|
|
55
55
|
trackPointsByIndices(indices?: number[] | undefined): void;
|
|
56
56
|
getTrackedPositionsMap(): Map<number, [number, number]>;
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
export declare class
|
|
1
|
+
export declare class PolygonSelection {
|
|
2
2
|
private canvas;
|
|
3
3
|
private ctx;
|
|
4
4
|
private isDrawing;
|
|
5
5
|
private points;
|
|
6
6
|
private graphDiv;
|
|
7
|
-
private
|
|
7
|
+
private onPolygonComplete?;
|
|
8
8
|
private boundStartDrawing;
|
|
9
9
|
private boundDraw;
|
|
10
10
|
private boundStopDrawing;
|
|
11
11
|
private resizeObserver;
|
|
12
|
-
constructor(graphDiv: HTMLElement,
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
constructor(graphDiv: HTMLElement, onPolygonComplete?: (points: [number, number][]) => void);
|
|
13
|
+
enablePolygonMode(): void;
|
|
14
|
+
disablePolygonMode(): void;
|
|
15
15
|
destroy(): void;
|
|
16
16
|
private resizeCanvas;
|
|
17
17
|
private startDrawing;
|
|
@@ -5,5 +5,5 @@ declare const meta: Meta<CosmosStoryProps>;
|
|
|
5
5
|
export declare const Worm: Story;
|
|
6
6
|
export declare const Radial: Story;
|
|
7
7
|
export declare const WithLabels: Story;
|
|
8
|
-
export declare const
|
|
8
|
+
export declare const PolygonSelection: Story;
|
|
9
9
|
export default meta;
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -648,7 +648,7 @@ export class Graph {
|
|
|
648
648
|
* The `top` and `bottom` coordinates should be from 0 to the height of the canvas.
|
|
649
649
|
* @returns A Float32Array containing the indices of points inside a rectangular area.
|
|
650
650
|
*/
|
|
651
|
-
public
|
|
651
|
+
public getPointsInRect (selection: [[number, number], [number, number]]): Float32Array {
|
|
652
652
|
if (this._isDestroyed || !this.reglInstance || !this.points) return new Float32Array()
|
|
653
653
|
const h = this.store.screenSize[1]
|
|
654
654
|
this.store.selectedArea = [[selection[0][0], (h - selection[1][1])], [selection[1][0], (h - selection[0][1])]]
|
|
@@ -664,20 +664,32 @@ export class Graph {
|
|
|
664
664
|
}
|
|
665
665
|
|
|
666
666
|
/**
|
|
667
|
-
* Get points indices inside a
|
|
668
|
-
* @param
|
|
667
|
+
* Get points indices inside a rectangular area.
|
|
668
|
+
* @param selection - Array of two corner points `[[left, top], [right, bottom]]`.
|
|
669
|
+
* The `left` and `right` coordinates should be from 0 to the width of the canvas.
|
|
670
|
+
* The `top` and `bottom` coordinates should be from 0 to the height of the canvas.
|
|
671
|
+
* @returns A Float32Array containing the indices of points inside a rectangular area.
|
|
672
|
+
* @deprecated Use `getPointsInRect` instead. This method will be removed in a future version.
|
|
673
|
+
*/
|
|
674
|
+
public getPointsInRange (selection: [[number, number], [number, number]]): Float32Array {
|
|
675
|
+
return this.getPointsInRect(selection)
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
/**
|
|
679
|
+
* Get points indices inside a polygon area.
|
|
680
|
+
* @param polygonPath - Array of points `[[x1, y1], [x2, y2], ..., [xn, yn]]` that defines the polygon.
|
|
669
681
|
* The coordinates should be from 0 to the width/height of the canvas.
|
|
670
|
-
* @returns A Float32Array containing the indices of points inside the
|
|
682
|
+
* @returns A Float32Array containing the indices of points inside the polygon area.
|
|
671
683
|
*/
|
|
672
|
-
public
|
|
684
|
+
public getPointsInPolygon (polygonPath: [number, number][]): Float32Array {
|
|
673
685
|
if (this._isDestroyed || !this.reglInstance || !this.points) return new Float32Array()
|
|
674
|
-
if (
|
|
686
|
+
if (polygonPath.length < 3) return new Float32Array() // Need at least 3 points for a polygon
|
|
675
687
|
|
|
676
688
|
const h = this.store.screenSize[1]
|
|
677
689
|
// Convert coordinates to WebGL coordinate system (flip Y)
|
|
678
|
-
const convertedPath =
|
|
679
|
-
this.points.
|
|
680
|
-
this.points.
|
|
690
|
+
const convertedPath = polygonPath.map(([x, y]) => [x, h - y] as [number, number])
|
|
691
|
+
this.points.updatePolygonPath(convertedPath)
|
|
692
|
+
this.points.findPointsOnPolygonSelection()
|
|
681
693
|
const pixels = readPixels(this.reglInstance, this.points.selectedFbo as regl.Framebuffer2D)
|
|
682
694
|
|
|
683
695
|
return pixels
|
|
@@ -692,7 +704,7 @@ export class Graph {
|
|
|
692
704
|
* @param selection - Array of two corner points `[[left, top], [right, bottom]]`.
|
|
693
705
|
* The `left` and `right` coordinates should be from 0 to the width of the canvas.
|
|
694
706
|
* The `top` and `bottom` coordinates should be from 0 to the height of the canvas. */
|
|
695
|
-
public
|
|
707
|
+
public selectPointsInRect (selection: [[number, number], [number, number]] | null): void {
|
|
696
708
|
if (this._isDestroyed || !this.reglInstance || !this.points) return
|
|
697
709
|
if (selection) {
|
|
698
710
|
const h = this.store.screenSize[1]
|
|
@@ -711,23 +723,33 @@ export class Graph {
|
|
|
711
723
|
this.points.updateGreyoutStatus()
|
|
712
724
|
}
|
|
713
725
|
|
|
714
|
-
/** Select points inside a
|
|
715
|
-
* @param
|
|
726
|
+
/** Select points inside a rectangular area.
|
|
727
|
+
* @param selection - Array of two corner points `[[left, top], [right, bottom]]`.
|
|
728
|
+
* The `left` and `right` coordinates should be from 0 to the width of the canvas.
|
|
729
|
+
* The `top` and `bottom` coordinates should be from 0 to the height of the canvas.
|
|
730
|
+
* @deprecated Use `selectPointsInRect` instead. This method will be removed in a future version.
|
|
731
|
+
*/
|
|
732
|
+
public selectPointsInRange (selection: [[number, number], [number, number]] | null): void {
|
|
733
|
+
return this.selectPointsInRect(selection)
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
/** Select points inside a polygon area.
|
|
737
|
+
* @param polygonPath - Array of points `[[x1, y1], [x2, y2], ..., [xn, yn]]` that defines the polygon.
|
|
716
738
|
* The coordinates should be from 0 to the width/height of the canvas.
|
|
717
739
|
* Set to null to clear selection. */
|
|
718
|
-
public
|
|
740
|
+
public selectPointsInPolygon (polygonPath: [number, number][] | null): void {
|
|
719
741
|
if (this._isDestroyed || !this.reglInstance || !this.points) return
|
|
720
|
-
if (
|
|
721
|
-
if (
|
|
722
|
-
console.warn('
|
|
742
|
+
if (polygonPath) {
|
|
743
|
+
if (polygonPath.length < 3) {
|
|
744
|
+
console.warn('Polygon path requires at least 3 points to form a polygon.')
|
|
723
745
|
return
|
|
724
746
|
}
|
|
725
747
|
|
|
726
748
|
const h = this.store.screenSize[1]
|
|
727
749
|
// Convert coordinates to WebGL coordinate system (flip Y)
|
|
728
|
-
const convertedPath =
|
|
729
|
-
this.points.
|
|
730
|
-
this.points.
|
|
750
|
+
const convertedPath = polygonPath.map(([x, y]) => [x, h - y] as [number, number])
|
|
751
|
+
this.points.updatePolygonPath(convertedPath)
|
|
752
|
+
this.points.findPointsOnPolygonSelection()
|
|
731
753
|
const pixels = readPixels(this.reglInstance, this.points.selectedFbo as regl.Framebuffer2D)
|
|
732
754
|
this.store.selectedIndices = pixels
|
|
733
755
|
.map((pixel, i) => {
|
|
@@ -3,16 +3,16 @@ precision highp float;
|
|
|
3
3
|
#endif
|
|
4
4
|
|
|
5
5
|
uniform sampler2D positionsTexture;
|
|
6
|
-
uniform sampler2D
|
|
7
|
-
uniform int
|
|
6
|
+
uniform sampler2D polygonPathTexture; // Texture containing polygon path points
|
|
7
|
+
uniform int polygonPathLength;
|
|
8
8
|
uniform float spaceSize;
|
|
9
9
|
uniform vec2 screenSize;
|
|
10
10
|
uniform mat3 transformationMatrix;
|
|
11
11
|
|
|
12
12
|
varying vec2 textureCoords;
|
|
13
13
|
|
|
14
|
-
// Get a point from the
|
|
15
|
-
vec2
|
|
14
|
+
// Get a point from the polygon path texture at a specific index
|
|
15
|
+
vec2 getPolygonPoint(sampler2D pathTexture, int index, int pathLength) {
|
|
16
16
|
if (index >= pathLength) return vec2(0.0);
|
|
17
17
|
|
|
18
18
|
// Calculate texture coordinates for the index
|
|
@@ -35,8 +35,8 @@ bool pointInPolygon(vec2 point, sampler2D pathTexture, int pathLength) {
|
|
|
35
35
|
|
|
36
36
|
int j = int(mod(float(i + 1), float(pathLength)));
|
|
37
37
|
|
|
38
|
-
vec2 pi =
|
|
39
|
-
vec2 pj =
|
|
38
|
+
vec2 pi = getPolygonPoint(pathTexture, i, pathLength);
|
|
39
|
+
vec2 pj = getPolygonPoint(pathTexture, j, pathLength);
|
|
40
40
|
|
|
41
41
|
if (((pi.y > point.y) != (pj.y > point.y)) &&
|
|
42
42
|
(point.x < (pj.x - pi.x) * (point.y - pi.y) / (pj.y - pi.y) + pi.x)) {
|
|
@@ -58,8 +58,8 @@ void main() {
|
|
|
58
58
|
|
|
59
59
|
gl_FragColor = vec4(0.0, 0.0, pointPosition.rg);
|
|
60
60
|
|
|
61
|
-
// Check if point center is inside the
|
|
62
|
-
if (pointInPolygon(screenPos,
|
|
61
|
+
// Check if point center is inside the polygon
|
|
62
|
+
if (pointInPolygon(screenPos, polygonPathTexture, polygonPathLength)) {
|
|
63
63
|
gl_FragColor.r = 1.0;
|
|
64
64
|
}
|
|
65
65
|
}
|
|
@@ -6,7 +6,7 @@ import { defaultConfigValues } from '@/graph/variables'
|
|
|
6
6
|
import drawPointsFrag from '@/graph/modules/Points/draw-points.frag'
|
|
7
7
|
import drawPointsVert from '@/graph/modules/Points/draw-points.vert'
|
|
8
8
|
import findPointsOnAreaSelectionFrag from '@/graph/modules/Points/find-points-on-area-selection.frag'
|
|
9
|
-
import
|
|
9
|
+
import findPointsOnPolygonSelectionFrag from '@/graph/modules/Points/find-points-on-polygon-selection.frag'
|
|
10
10
|
import drawHighlightedFrag from '@/graph/modules/Points/draw-highlighted.frag'
|
|
11
11
|
import drawHighlightedVert from '@/graph/modules/Points/draw-highlighted.vert'
|
|
12
12
|
import findHoveredPointFrag from '@/graph/modules/Points/find-hovered-point.frag'
|
|
@@ -42,7 +42,7 @@ export class Points extends CoreModule {
|
|
|
42
42
|
private updatePositionCommand: regl.DrawCommand | undefined
|
|
43
43
|
private dragPointCommand: regl.DrawCommand | undefined
|
|
44
44
|
private findPointsOnAreaSelectionCommand: regl.DrawCommand | undefined
|
|
45
|
-
private
|
|
45
|
+
private findPointsOnPolygonSelectionCommand: regl.DrawCommand | undefined
|
|
46
46
|
private findHoveredPointCommand: regl.DrawCommand | undefined
|
|
47
47
|
private clearHoveredFboCommand: regl.DrawCommand | undefined
|
|
48
48
|
private clearSampledPointsFboCommand: regl.DrawCommand | undefined
|
|
@@ -53,9 +53,9 @@ export class Points extends CoreModule {
|
|
|
53
53
|
private greyoutStatusTexture: regl.Texture2D | undefined
|
|
54
54
|
private sizeTexture: regl.Texture2D | undefined
|
|
55
55
|
private trackedIndicesTexture: regl.Texture2D | undefined
|
|
56
|
-
private
|
|
57
|
-
private
|
|
58
|
-
private
|
|
56
|
+
private polygonPathTexture: regl.Texture2D | undefined
|
|
57
|
+
private polygonPathFbo: regl.Framebuffer2D | undefined
|
|
58
|
+
private polygonPathLength = 0
|
|
59
59
|
private drawPointIndices: regl.Buffer | undefined
|
|
60
60
|
private hoveredPointIndices: regl.Buffer | undefined
|
|
61
61
|
private sampledPointIndices: regl.Buffer | undefined
|
|
@@ -285,9 +285,9 @@ export class Points extends CoreModule {
|
|
|
285
285
|
})
|
|
286
286
|
}
|
|
287
287
|
|
|
288
|
-
if (!this.
|
|
289
|
-
this.
|
|
290
|
-
frag:
|
|
288
|
+
if (!this.findPointsOnPolygonSelectionCommand) {
|
|
289
|
+
this.findPointsOnPolygonSelectionCommand = reglInstance({
|
|
290
|
+
frag: findPointsOnPolygonSelectionFrag,
|
|
291
291
|
vert: updateVert,
|
|
292
292
|
framebuffer: () => this.selectedFbo as regl.Framebuffer2D,
|
|
293
293
|
primitive: 'triangle strip',
|
|
@@ -300,8 +300,8 @@ export class Points extends CoreModule {
|
|
|
300
300
|
spaceSize: () => store.adjustedSpaceSize,
|
|
301
301
|
screenSize: () => store.screenSize,
|
|
302
302
|
transformationMatrix: () => store.transform,
|
|
303
|
-
|
|
304
|
-
|
|
303
|
+
polygonPathTexture: () => this.polygonPathTexture,
|
|
304
|
+
polygonPathLength: () => this.polygonPathLength,
|
|
305
305
|
},
|
|
306
306
|
})
|
|
307
307
|
}
|
|
@@ -573,26 +573,26 @@ export class Points extends CoreModule {
|
|
|
573
573
|
this.findPointsOnAreaSelectionCommand?.()
|
|
574
574
|
}
|
|
575
575
|
|
|
576
|
-
public
|
|
577
|
-
this.
|
|
576
|
+
public findPointsOnPolygonSelection (): void {
|
|
577
|
+
this.findPointsOnPolygonSelectionCommand?.()
|
|
578
578
|
}
|
|
579
579
|
|
|
580
|
-
public
|
|
580
|
+
public updatePolygonPath (polygonPath: [number, number][]): void {
|
|
581
581
|
const { reglInstance } = this
|
|
582
|
-
this.
|
|
582
|
+
this.polygonPathLength = polygonPath.length
|
|
583
583
|
|
|
584
|
-
if (
|
|
585
|
-
this.
|
|
586
|
-
this.
|
|
584
|
+
if (polygonPath.length === 0) {
|
|
585
|
+
this.polygonPathTexture = undefined
|
|
586
|
+
this.polygonPathFbo = undefined
|
|
587
587
|
return
|
|
588
588
|
}
|
|
589
589
|
|
|
590
590
|
// Calculate texture size (square texture)
|
|
591
|
-
const textureSize = Math.ceil(Math.sqrt(
|
|
591
|
+
const textureSize = Math.ceil(Math.sqrt(polygonPath.length))
|
|
592
592
|
const textureData = new Float32Array(textureSize * textureSize * 4)
|
|
593
593
|
|
|
594
|
-
// Fill texture with
|
|
595
|
-
for (const [i, point] of
|
|
594
|
+
// Fill texture with polygon path points
|
|
595
|
+
for (const [i, point] of polygonPath.entries()) {
|
|
596
596
|
const [x, y] = point
|
|
597
597
|
textureData[i * 4] = x
|
|
598
598
|
textureData[i * 4 + 1] = y
|
|
@@ -600,17 +600,17 @@ export class Points extends CoreModule {
|
|
|
600
600
|
textureData[i * 4 + 3] = 0 // unused
|
|
601
601
|
}
|
|
602
602
|
|
|
603
|
-
if (!this.
|
|
604
|
-
this.
|
|
603
|
+
if (!this.polygonPathTexture) this.polygonPathTexture = reglInstance.texture()
|
|
604
|
+
this.polygonPathTexture({
|
|
605
605
|
data: textureData,
|
|
606
606
|
width: textureSize,
|
|
607
607
|
height: textureSize,
|
|
608
608
|
type: 'float',
|
|
609
609
|
})
|
|
610
610
|
|
|
611
|
-
if (!this.
|
|
612
|
-
this.
|
|
613
|
-
color: this.
|
|
611
|
+
if (!this.polygonPathFbo) this.polygonPathFbo = reglInstance.framebuffer()
|
|
612
|
+
this.polygonPathFbo({
|
|
613
|
+
color: this.polygonPathTexture,
|
|
614
614
|
depth: false,
|
|
615
615
|
stencil: false,
|
|
616
616
|
})
|
|
@@ -237,34 +237,52 @@ The `fitViewByPointPositions` method centers and zooms the view to fit the point
|
|
|
237
237
|
* **`duration`** (Number, optional): The duration of the animation in milliseconds. Default is 250 ms.
|
|
238
238
|
* **`padding`** (Number, optional): The padding around the viewport in percentage. This value should be between 0 and 1. Default is 0.1 (10% padding).
|
|
239
239
|
|
|
240
|
-
### <a name="
|
|
240
|
+
### <a name="get_points_in_rect" href="#get_points_in_rect">#</a> graph.<b>getPointsInRect</b>(<i>selection</i>)
|
|
241
241
|
|
|
242
242
|
Get points as a Float32Array within a rectangular area defined by two corner points `[[left, top], [right, bottom]]`. The `left` and `right` values represent the horizontal position in pixels, relative to the left edge of the canvas, with `0` being the leftmost position and the width of the canvas being the rightmost position.
|
|
243
243
|
|
|
244
244
|
The `top` and `bottom` values represent the vertical position in pixels, relative to the top edge of the canvas, with `0` being the topmost position and the height of the canvas being the bottommost position.
|
|
245
245
|
|
|
246
|
-
|
|
246
|
+
* **`selection`** (Array): An array containing two coordinate arrays representing the corners of the selection rectangle in the format `[[left, top], [right, bottom]]`.
|
|
247
|
+
|
|
248
|
+
**Returns:** A Float32Array containing the indices of points inside the rectangular area.
|
|
249
|
+
|
|
250
|
+
### <a name="get_points_in_range" href="#get_points_in_range">#</a> graph.<b>getPointsInRange</b>(<i>selection</i>) <b style={{ color: 'orange' }}>[DEPRECATED]</b>
|
|
251
|
+
|
|
252
|
+
**⚠️ Deprecated:** Use `getPointsInRect` instead. This method will be removed in a future version.
|
|
253
|
+
|
|
254
|
+
Get points as a Float32Array within a rectangular area defined by two corner points `[[left, top], [right, bottom]]`. This method has the same functionality as `getPointsInRect`.
|
|
255
|
+
|
|
256
|
+
### <a name="select_points_in_rect" href="#select_points_in_rect">#</a> graph.<b>selectPointsInRect</b>(<i>selection</i>)
|
|
247
257
|
|
|
248
258
|
Select points within a rectangular area defined by two corner points `[[left, top], [right, bottom]]`. The `left` and `right` values represent the horizontal position in pixels, relative to the left edge of the canvas, with `0` being the leftmost position and the width of the canvas being the rightmost position.
|
|
249
259
|
|
|
250
260
|
The `top` and `bottom` values represent the vertical position in pixels, relative to the top edge of the canvas, with `0` being the topmost position and the height of the canvas being the bottommost position.
|
|
251
261
|
|
|
252
|
-
|
|
262
|
+
* **`selection`** (Array | null): An array containing two coordinate arrays representing the corners of the selection rectangle in the format `[[left, top], [right, bottom]]`, or `null` to clear the current selection.
|
|
263
|
+
|
|
264
|
+
### <a name="select_points_in_range" href="#select_points_in_range">#</a> graph.<b>selectPointsInRange</b>(<i>selection</i>) <b style={{ color: 'orange' }}>[DEPRECATED]</b>
|
|
265
|
+
|
|
266
|
+
**⚠️ Deprecated:** Use `selectPointsInRect` instead. This method will be removed in a future version.
|
|
267
|
+
|
|
268
|
+
Select points within a rectangular area defined by two corner points `[[left, top], [right, bottom]]`. This method has the same functionality as `selectPointsInRect`.
|
|
269
|
+
|
|
270
|
+
### <a name="get_points_in_polygon" href="#get_points_in_polygon">#</a> graph.<b>getPointsInPolygon</b>(<i>polygonPath</i>)
|
|
253
271
|
|
|
254
|
-
Get points as a Float32Array within a
|
|
272
|
+
Get points as a Float32Array within a polygon area defined by an array of coordinate points.
|
|
255
273
|
|
|
256
|
-
* **`
|
|
274
|
+
* **`polygonPath`** (Array): An array of coordinate points in the format `[[x1, y1], [x2, y2], ..., [xN, yN]]` that defines the polygon. The coordinates should be in pixels relative to the canvas, where:
|
|
257
275
|
- **`x`**: Horizontal position from 0 to the width of the canvas
|
|
258
276
|
- **`y`**: Vertical position from 0 to the height of the canvas
|
|
259
277
|
- The polygon requires at least 3 points to form a valid selection area
|
|
260
278
|
|
|
261
|
-
**Returns:** A Float32Array containing the indices of points inside the
|
|
279
|
+
**Returns:** A Float32Array containing the indices of points inside the polygon area.
|
|
262
280
|
|
|
263
|
-
### <a name="
|
|
281
|
+
### <a name="select_points_in_polygon" href="#select_points_in_polygon">#</a> graph.<b>selectPointsInPolygon</b>(<i>polygonPath</i>)
|
|
264
282
|
|
|
265
|
-
Select points within a
|
|
283
|
+
Select points within a polygon area defined by an array of coordinate points. This method combines the functionality of `getPointsInPolygon` with point selection, making the identified points visually selected in the graph.
|
|
266
284
|
|
|
267
|
-
* **`
|
|
285
|
+
* **`polygonPath`** (Array | null): An array of coordinate points in the format `[[x1, y1], [x2, y2], ..., [xN, yN]]` that defines the polygon, or `null` to clear the current selection. The coordinates should be in pixels relative to the canvas, where:
|
|
268
286
|
- **`x`**: Horizontal position from 0 to the width of the canvas
|
|
269
287
|
- **`y`**: Vertical position from 0 to the height of the canvas
|
|
270
288
|
- The polygon requires at least 3 points to form a valid selection area
|
|
@@ -119,7 +119,7 @@ export const basicSetUp = (): { graph: Graph; div: HTMLDivElement} => {
|
|
|
119
119
|
const top = getRandomInRange([h / 4, h / 2])
|
|
120
120
|
const bottom = getRandomInRange([top, (h * 3) / 4])
|
|
121
121
|
pause()
|
|
122
|
-
graph.
|
|
122
|
+
graph.selectPointsInRect([
|
|
123
123
|
[left, top],
|
|
124
124
|
[right, bottom],
|
|
125
125
|
])
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Graph } from '@cosmos.gl/graph'
|
|
2
2
|
import { createCosmos } from '../../create-cosmos'
|
|
3
3
|
import { generateMeshData } from '../../generate-mesh-data'
|
|
4
|
-
import {
|
|
4
|
+
import { PolygonSelection } from './polygon'
|
|
5
5
|
|
|
6
|
-
export const
|
|
6
|
+
export const polygonSelection = (): {div: HTMLDivElement; graph: Graph; destroy: () => void } => {
|
|
7
7
|
const nClusters = 25
|
|
8
8
|
const { pointPositions, pointColors, pointClusters } = generateMeshData(150, 150, nClusters, 1.0)
|
|
9
9
|
|
|
@@ -26,24 +26,24 @@ export const lassoSelection = (): {div: HTMLDivElement; graph: Graph; destroy: (
|
|
|
26
26
|
|
|
27
27
|
graph.setZoomLevel(0.4)
|
|
28
28
|
|
|
29
|
-
const
|
|
30
|
-
graph.
|
|
29
|
+
const polygonSelection = new PolygonSelection(div, (polygonPoints) => {
|
|
30
|
+
graph.selectPointsInPolygon(polygonPoints)
|
|
31
31
|
})
|
|
32
32
|
|
|
33
33
|
const actionsDiv = document.createElement('div')
|
|
34
34
|
actionsDiv.className = 'actions'
|
|
35
35
|
div.appendChild(actionsDiv)
|
|
36
36
|
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
const polygonButton = document.createElement('div')
|
|
38
|
+
polygonButton.className = 'action'
|
|
39
|
+
polygonButton.textContent = 'Enable Polygon Selection'
|
|
40
|
+
polygonButton.addEventListener('click', () => {
|
|
41
|
+
polygonSelection.enablePolygonMode()
|
|
42
42
|
})
|
|
43
|
-
actionsDiv.appendChild(
|
|
43
|
+
actionsDiv.appendChild(polygonButton)
|
|
44
44
|
|
|
45
45
|
const destroy = (): void => {
|
|
46
|
-
|
|
46
|
+
polygonSelection.destroy()
|
|
47
47
|
if (actionsDiv.parentNode) {
|
|
48
48
|
actionsDiv.parentNode.removeChild(actionsDiv)
|
|
49
49
|
}
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import './style.css'
|
|
2
2
|
|
|
3
|
-
export class
|
|
3
|
+
export class PolygonSelection {
|
|
4
4
|
private canvas: HTMLCanvasElement
|
|
5
5
|
private ctx: CanvasRenderingContext2D
|
|
6
6
|
private isDrawing = false
|
|
7
7
|
private points: Array<{ x: number; y: number }> = []
|
|
8
8
|
private graphDiv: HTMLElement
|
|
9
|
-
private
|
|
9
|
+
private onPolygonComplete?: (points: [number, number][]) => void
|
|
10
10
|
private boundStartDrawing: (e: MouseEvent) => void
|
|
11
11
|
private boundDraw: (e: MouseEvent) => void
|
|
12
12
|
private boundStopDrawing: () => void
|
|
13
13
|
private resizeObserver: ResizeObserver
|
|
14
14
|
|
|
15
|
-
public constructor (graphDiv: HTMLElement,
|
|
15
|
+
public constructor (graphDiv: HTMLElement, onPolygonComplete?: (points: [number, number][]) => void) {
|
|
16
16
|
this.graphDiv = graphDiv
|
|
17
|
-
this.
|
|
17
|
+
this.onPolygonComplete = onPolygonComplete
|
|
18
18
|
|
|
19
19
|
// Bind event handlers
|
|
20
20
|
this.boundStartDrawing = this.startDrawing.bind(this)
|
|
@@ -23,7 +23,7 @@ export class LassoSelection {
|
|
|
23
23
|
|
|
24
24
|
// Create canvas
|
|
25
25
|
this.canvas = document.createElement('canvas')
|
|
26
|
-
this.canvas.className = '
|
|
26
|
+
this.canvas.className = 'polygon-canvas'
|
|
27
27
|
|
|
28
28
|
const ctx = this.canvas.getContext('2d')
|
|
29
29
|
if (!ctx) throw new Error('Could not get canvas context')
|
|
@@ -37,7 +37,7 @@ export class LassoSelection {
|
|
|
37
37
|
this.resizeObserver.observe(this.graphDiv)
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
public
|
|
40
|
+
public enablePolygonMode (): void {
|
|
41
41
|
this.canvas.style.pointerEvents = 'auto'
|
|
42
42
|
this.canvas.style.cursor = 'crosshair'
|
|
43
43
|
|
|
@@ -47,7 +47,7 @@ export class LassoSelection {
|
|
|
47
47
|
this.canvas.addEventListener('mouseup', this.boundStopDrawing)
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
public
|
|
50
|
+
public disablePolygonMode (): void {
|
|
51
51
|
this.canvas.style.pointerEvents = 'none'
|
|
52
52
|
this.canvas.style.cursor = 'default'
|
|
53
53
|
|
|
@@ -61,7 +61,7 @@ export class LassoSelection {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
public destroy (): void {
|
|
64
|
-
this.
|
|
64
|
+
this.disablePolygonMode()
|
|
65
65
|
this.resizeObserver.disconnect()
|
|
66
66
|
if (this.canvas.parentNode) {
|
|
67
67
|
this.canvas.parentNode.removeChild(this.canvas)
|
|
@@ -124,20 +124,20 @@ export class LassoSelection {
|
|
|
124
124
|
this.ctx.closePath()
|
|
125
125
|
this.ctx.stroke()
|
|
126
126
|
|
|
127
|
-
const
|
|
128
|
-
const
|
|
129
|
-
const
|
|
130
|
-
if (
|
|
131
|
-
|
|
127
|
+
const polygonPoints: [number, number][] = this.points.map(p => [p.x, p.y])
|
|
128
|
+
const firstPolygonPoint = polygonPoints[0]
|
|
129
|
+
const lastPolygonPoint = polygonPoints[polygonPoints.length - 1]
|
|
130
|
+
if (firstPolygonPoint && lastPolygonPoint && (firstPolygonPoint[0] !== lastPolygonPoint[0] || firstPolygonPoint[1] !== lastPolygonPoint[1])) {
|
|
131
|
+
polygonPoints.push(firstPolygonPoint)
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
if (this.
|
|
135
|
-
this.
|
|
134
|
+
if (this.onPolygonComplete) {
|
|
135
|
+
this.onPolygonComplete(polygonPoints)
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
const pixelRatio = window.devicePixelRatio || 1
|
|
140
140
|
this.ctx.clearRect(0, 0, this.canvas.width / pixelRatio, this.canvas.height / pixelRatio)
|
|
141
|
-
this.
|
|
141
|
+
this.disablePolygonMode()
|
|
142
142
|
}
|
|
143
143
|
}
|
|
@@ -4,7 +4,7 @@ import { createStory, Story } from '@/graph/stories/create-story'
|
|
|
4
4
|
import { withLabels } from './clusters/with-labels'
|
|
5
5
|
import { worm } from './clusters/worm'
|
|
6
6
|
import { radial } from './clusters/radial'
|
|
7
|
-
import {
|
|
7
|
+
import { polygonSelection } from './clusters/polygon-selection'
|
|
8
8
|
|
|
9
9
|
import createCosmosRaw from './create-cosmos?raw'
|
|
10
10
|
import generateMeshDataRaw from './generate-mesh-data?raw'
|
|
@@ -12,9 +12,9 @@ import withLabelsStoryRaw from './clusters/with-labels?raw'
|
|
|
12
12
|
import createClusterLabelsRaw from './create-cluster-labels?raw'
|
|
13
13
|
import wormStory from './clusters/worm?raw'
|
|
14
14
|
import radialStory from './clusters/radial?raw'
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
import
|
|
15
|
+
import polygonSelectionStory from './clusters/polygon-selection?raw'
|
|
16
|
+
import polygonSelectionStyleRaw from './clusters/polygon-selection/style.css?raw'
|
|
17
|
+
import polygonSelectionPolygonRaw from './clusters/polygon-selection/polygon.ts?raw'
|
|
18
18
|
|
|
19
19
|
const meta: Meta<CosmosStoryProps> = {
|
|
20
20
|
title: 'Examples/Clusters',
|
|
@@ -61,14 +61,14 @@ export const WithLabels: Story = {
|
|
|
61
61
|
},
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
export const
|
|
65
|
-
...createStory(
|
|
64
|
+
export const PolygonSelection: Story = {
|
|
65
|
+
...createStory(polygonSelection),
|
|
66
66
|
parameters: {
|
|
67
67
|
sourceCode: [
|
|
68
|
-
{ name: 'Story', code:
|
|
69
|
-
{ name: '
|
|
68
|
+
{ name: 'Story', code: polygonSelectionStory },
|
|
69
|
+
{ name: 'polygon.ts', code: polygonSelectionPolygonRaw },
|
|
70
70
|
...sourceCodeAddonParams,
|
|
71
|
-
{ name: 'style.css', code:
|
|
71
|
+
{ name: 'style.css', code: polygonSelectionStyleRaw },
|
|
72
72
|
],
|
|
73
73
|
},
|
|
74
74
|
}
|