@memberjunction/ng-clustering 0.0.1 → 5.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +441 -27
  2. package/dist/__tests__/clustering-service.test.d.ts +2 -0
  3. package/dist/__tests__/clustering-service.test.d.ts.map +1 -0
  4. package/dist/__tests__/clustering-service.test.js +487 -0
  5. package/dist/__tests__/clustering-service.test.js.map +1 -0
  6. package/dist/__tests__/clustering-types.test.d.ts +2 -0
  7. package/dist/__tests__/clustering-types.test.d.ts.map +1 -0
  8. package/dist/__tests__/clustering-types.test.js +254 -0
  9. package/dist/__tests__/clustering-types.test.js.map +1 -0
  10. package/dist/__tests__/index.test.d.ts +2 -0
  11. package/dist/__tests__/index.test.d.ts.map +1 -0
  12. package/dist/__tests__/index.test.js +7 -0
  13. package/dist/__tests__/index.test.js.map +1 -0
  14. package/dist/__tests__/scatter-component-logic.test.d.ts +2 -0
  15. package/dist/__tests__/scatter-component-logic.test.d.ts.map +1 -0
  16. package/dist/__tests__/scatter-component-logic.test.js +494 -0
  17. package/dist/__tests__/scatter-component-logic.test.js.map +1 -0
  18. package/dist/lib/cluster-config-panel.component.d.ts +274 -0
  19. package/dist/lib/cluster-config-panel.component.d.ts.map +1 -0
  20. package/dist/lib/cluster-config-panel.component.js +732 -0
  21. package/dist/lib/cluster-config-panel.component.js.map +1 -0
  22. package/dist/lib/cluster-scatter.component.d.ts +572 -0
  23. package/dist/lib/cluster-scatter.component.d.ts.map +1 -0
  24. package/dist/lib/cluster-scatter.component.js +1410 -0
  25. package/dist/lib/cluster-scatter.component.js.map +1 -0
  26. package/dist/lib/clustering.module.d.ts +12 -0
  27. package/dist/lib/clustering.module.d.ts.map +1 -0
  28. package/dist/lib/clustering.module.js +38 -0
  29. package/dist/lib/clustering.module.js.map +1 -0
  30. package/dist/lib/clustering.service.d.ts +43 -0
  31. package/dist/lib/clustering.service.d.ts.map +1 -0
  32. package/dist/lib/clustering.service.js +253 -0
  33. package/dist/lib/clustering.service.js.map +1 -0
  34. package/dist/lib/clustering.types.d.ts +271 -0
  35. package/dist/lib/clustering.types.d.ts.map +1 -0
  36. package/dist/lib/clustering.types.js +74 -0
  37. package/dist/lib/clustering.types.js.map +1 -0
  38. package/dist/public-api.d.ts +6 -0
  39. package/dist/public-api.d.ts.map +1 -0
  40. package/dist/public-api.js +11 -0
  41. package/dist/public-api.js.map +1 -0
  42. package/package.json +41 -6
package/README.md CHANGED
@@ -1,45 +1,459 @@
1
1
  # @memberjunction/ng-clustering
2
2
 
3
- ## ⚠️ IMPORTANT NOTICE ⚠️
3
+ Reusable Angular components for interactive cluster visualization. Provides an SVG scatter plot with a slide-in detail panel, a floating configuration panel, LLM-generated cluster labels, save/restore of visualizations, and a headless clustering service that wraps K-Means, DBSCAN, UMAP, and PCA into a single pipeline.
4
4
 
5
- **This package is created solely for the purpose of setting up OIDC (OpenID Connect) trusted publishing with npm.**
5
+ ## Architecture
6
6
 
7
- This is **NOT** a functional package and contains **NO** code or functionality beyond the OIDC setup configuration.
7
+ ```
8
+ +---------------------------+ +-------------------------------+
9
+ | mj-cluster-config-panel | | mj-cluster-scatter |
10
+ | (floating config UI) | | (SVG scatter plot) |
11
+ | | | |
12
+ | Entity picker | | Points + Clusters -> dots |
13
+ | Algorithm (K-Means/DBSCAN)| | Zoom / Pan via viewBox |
14
+ | Distance metric | | Tooltip on hover |
15
+ | Run / Save buttons | | Legend overlay |
16
+ | Result metrics display | | Selection rings |
17
+ +--------+------------------+ +--------+----------------------+
18
+ | ^
19
+ | RunClustering (ClusterConfig) | Points, Clusters
20
+ v |
21
+ +--------+-----------------------------------+--+
22
+ | ClusteringService |
23
+ | |
24
+ | RunClustering(vectors, config) |
25
+ | 1. K-Means / DBSCAN via SimpleVectorService|
26
+ | 2. UMAP (or PCA fallback) to 2D |
27
+ | 3. Returns ClusterVisualizationResult |
28
+ +-----------------+-----------------------------+
29
+ |
30
+ v
31
+ @memberjunction/ai-vectors-memory
32
+ (SimpleVectorService)
33
+ ```
8
34
 
9
- ## Purpose
35
+ The config panel emits a `ClusterConfig`; the parent fetches vectors (from a database, API, or any source), passes them to `ClusteringService.RunClustering()`, and feeds the result into the scatter component. Clicking a point opens a detail panel slide-in showing entity metadata, cluster members, and an "Open Record" button. Cluster labels can be generated via LLM using the "Cluster Naming" AI prompt. Visualizations can be saved and restored with full viewport state and cluster labels.
10
36
 
11
- This package exists to:
12
- 1. Configure OIDC trusted publishing for the package name `@memberjunction/ng-clustering`
13
- 2. Enable secure, token-less publishing from CI/CD workflows
14
- 3. Establish provenance for packages published under this name
37
+ ## Installation
15
38
 
16
- ## What is OIDC Trusted Publishing?
39
+ The package is part of the MemberJunction monorepo. Add it to your Angular module or standalone component imports:
17
40
 
18
- OIDC trusted publishing allows package maintainers to publish packages directly from their CI/CD workflows without needing to manage npm access tokens. Instead, it uses OpenID Connect to establish trust between the CI/CD provider (like GitHub Actions) and npm.
41
+ ```typescript
42
+ import { ClusteringModule } from '@memberjunction/ng-clustering';
19
43
 
20
- ## Setup Instructions
44
+ @NgModule({
45
+ imports: [ClusteringModule],
46
+ })
47
+ export class MyFeatureModule {}
48
+ ```
21
49
 
22
- To properly configure OIDC trusted publishing for this package:
50
+ Peer dependencies: `@angular/core`, `@angular/common`, `@angular/forms` (all 21.x).
23
51
 
24
- 1. Go to [npmjs.com](https://www.npmjs.com/) and navigate to your package settings
25
- 2. Configure the trusted publisher (e.g., GitHub Actions)
26
- 3. Specify the repository and workflow that should be allowed to publish
27
- 4. Use the configured workflow to publish your actual package
52
+ ## Quick Start
28
53
 
29
- ## DO NOT USE THIS PACKAGE
54
+ ```html
55
+ <!-- my-dashboard.component.html -->
56
+ <mj-cluster-scatter
57
+ [Points]="result?.Points ?? []"
58
+ [Clusters]="result?.Clusters ?? []"
59
+ [IsLoading]="isRunning"
60
+ (PointClicked)="onPointClicked($event)">
61
+ </mj-cluster-scatter>
30
62
 
31
- This package is a placeholder for OIDC configuration only. It:
32
- - Contains no executable code
33
- - Provides no functionality
34
- - Should not be installed as a dependency
35
- - Exists only for administrative purposes
63
+ <mj-cluster-config-panel
64
+ [IsRunning]="isRunning"
65
+ [Metrics]="result?.Metrics ?? null"
66
+ [EntityOptions]="entityOptions"
67
+ (RunClustering)="onRun($event)">
68
+ </mj-cluster-config-panel>
69
+ ```
36
70
 
37
- ## More Information
71
+ ```typescript
72
+ // my-dashboard.component.ts
73
+ import { ClusteringService, ClusterConfig, ClusterVisualizationResult } from '@memberjunction/ng-clustering';
38
74
 
39
- For more details about npm's trusted publishing feature, see:
40
- - [npm Trusted Publishing Documentation](https://docs.npmjs.com/generating-provenance-statements)
41
- - [GitHub Actions OIDC Documentation](https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect)
75
+ export class MyDashboardComponent {
76
+ private clusteringService = inject(ClusteringService);
77
+ result: ClusterVisualizationResult | null = null;
78
+ isRunning = false;
79
+
80
+ async onRun(config: ClusterConfig): Promise<void> {
81
+ this.isRunning = true;
82
+ const vectors = await this.fetchMyVectors(config);
83
+ this.result = await this.clusteringService.RunClustering(vectors, config);
84
+ this.isRunning = false;
85
+ }
86
+ }
87
+ ```
88
+
89
+ ---
90
+
91
+ ## API Reference: `ClusterScatterComponent`
92
+
93
+ **Selector:** `mj-cluster-scatter`
94
+
95
+ ### Inputs
96
+
97
+ | Input | Type | Default | Description |
98
+ |---|---|---|---|
99
+ | `Points` | `ClusterPoint[]` | `[]` | 2D-projected points to render |
100
+ | `Clusters` | `ClusterInfo[]` | `[]` | Cluster summaries for legend and color mapping |
101
+ | `IsLoading` | `boolean` | `false` | Show loading overlay |
102
+ | `DotRadius` | `number` | `5` | Base radius (SVG units) for each data point |
103
+ | `DotOpacity` | `number` | `0.75` | Base opacity for dots (0--1) |
104
+ | `HighlightRadius` | `number` | `8` | Radius for hovered/selected point rings |
105
+ | `ShowLegend` | `boolean` | `true` | Show the color-coded cluster legend |
106
+ | `ShowTooltip` | `boolean` | `true` | Show the tooltip popup on hover |
107
+ | `TooltipFields` | `string[]` | `[]` | Metadata keys to show in tooltip (empty = all) |
108
+ | `ColorPalette` | `string[]` | `CLUSTER_COLORS` | Override cluster colors (wraps around) |
109
+ | `EnableZoom` | `boolean` | `true` | Enable mouse-wheel zoom |
110
+ | `EnablePan` | `boolean` | `true` | Enable click-and-drag pan |
111
+ | `AnimateTransitions` | `boolean` | `true` | Animate dot/ring transitions |
112
+ | `SelectedPointIds` | `Set<string>` | `new Set()` | Externally controlled selection (by VectorKey) |
113
+ | `MinZoom` | `number` | `0.5` | Minimum zoom level (viewBox multiplier) |
114
+ | `MaxZoom` | `number` | `10` | Maximum zoom level (viewBox multiplier) |
115
+
116
+ ### Outputs
117
+
118
+ #### Standard Events
119
+
120
+ | Output | Payload | Description |
121
+ |---|---|---|
122
+ | `PointClicked` | `ClusterPoint` | A point was clicked |
123
+ | `PointHovered` | `ClusterPoint \| null` | Mouse entered/left a point |
124
+ | `AfterClusteringComplete` | `ClusterVisualizationResult` | New data received and centroids computed |
125
+ | `ClusterSelected` | `ClusterSelectedEvent` | Legend item clicked |
126
+ | `SelectionChanged` | `Set<string>` | Selection set changed (user or programmatic) |
127
+ | `ViewportChanged` | `ViewportRect` | Visible area changed after zoom/pan |
128
+
129
+ #### Cancelable Events
130
+
131
+ These fire **before** the corresponding action. Set `event.Cancel = true` to suppress it.
132
+
133
+ | Output | Payload | Cancels |
134
+ |---|---|---|
135
+ | `BeforePointClick` | `CancelableEvent<ClusterPoint>` | Suppresses `PointClicked` |
136
+ | `BeforePointHover` | `CancelableEvent<ClusterPoint>` | Suppresses tooltip show |
137
+ | `BeforeZoom` | `CancelableEvent<ViewportRect>` | Suppresses zoom/pan |
138
+
139
+ ### Public Methods
140
+
141
+ | Method | Signature | Description |
142
+ |---|---|---|
143
+ | `ZoomToCluster` | `(clusterId: number): void` | Animate zoom to center on a cluster |
144
+ | `ResetZoom` | `(): void` | Reset to default viewport |
145
+ | `GetVisiblePoints` | `(): ClusterPoint[]` | Return points in current viewport |
146
+ | `SelectPoints` | `(ids: string[]): void` | Add points to selection |
147
+ | `ClearSelection` | `(): void` | Clear all selected points |
148
+ | `ExportSVG` | `(): string` | Export scatter plot as SVG string |
149
+ | `HighlightCluster` | `(clusterId: number): void` | Select all points in a cluster |
150
+
151
+ ---
152
+
153
+ ## API Reference: `ClusterConfigPanelComponent`
154
+
155
+ **Selector:** `mj-cluster-config-panel`
156
+
157
+ ### Inputs
158
+
159
+ | Input | Type | Default | Description |
160
+ |---|---|---|---|
161
+ | `IsRunning` | `boolean` | `false` | Disable Run button and show spinner |
162
+ | `Metrics` | `ClusterMetrics \| null` | `null` | Display result metrics when non-null |
163
+ | `EntityOptions` | `ClusterConfigPanelEntityOption[]` | `[]` | Entity choices for the dropdown |
164
+ | `ShowSaveButton` | `boolean` | `true` | Show the "Save this visualization" link |
165
+ | `ShowAlgorithmPicker` | `boolean` | `true` | Show the algorithm dropdown |
166
+ | `ShowMetricPicker` | `boolean` | `true` | Show the distance metric dropdown |
167
+ | `DefaultAlgorithm` | `'kmeans' \| 'dbscan'` | `'kmeans'` | Initial algorithm selection |
168
+ | `AvailableEntities` | `string[]` | `[]` | Filter entity picker (empty = show all) |
169
+ | `Collapsed` | `boolean` | `false` | Start panel in collapsed state |
170
+
171
+ ### Outputs
172
+
173
+ #### Standard Events
174
+
175
+ | Output | Payload | Description |
176
+ |---|---|---|
177
+ | `RunClustering` | `ClusterConfig` | Run button clicked (after validation) |
178
+ | `SaveVisualization` | `void` | Save link clicked (after validation) |
179
+ | `ConfigChanged` | `ClusterConfig` | Any config value changed |
180
+ | `AlgorithmChanged` | `ClusterAlgorithm` | Algorithm dropdown changed |
181
+
182
+ #### Cancelable Events
183
+
184
+ | Output | Payload | Cancels |
185
+ |---|---|---|
186
+ | `BeforeRunClustering` | `CancelableEvent<ClusterConfig>` | Suppresses `RunClustering` |
187
+ | `BeforeSave` | `CancelableEvent<ClusterConfig>` | Suppresses `SaveVisualization` |
42
188
 
43
189
  ---
44
190
 
45
- **Maintained for OIDC setup purposes only**
191
+ ## Event Architecture: Cancelable Pattern
192
+
193
+ All `BeforeXXX` events use the `CancelableEvent<T>` interface:
194
+
195
+ ```typescript
196
+ export interface CancelableEvent<T = unknown> {
197
+ Data: T; // The event payload
198
+ Cancel: boolean; // Set to true to prevent the default action
199
+ }
200
+ ```
201
+
202
+ The component creates a `CancelableEvent`, emits it synchronously, then checks `Cancel` before proceeding. This works because Angular `EventEmitter.emit()` calls subscribers synchronously.
203
+
204
+ ### Example: Validate Before Run
205
+
206
+ ```typescript
207
+ onBeforeRun(event: CancelableEvent<ClusterConfig>): void {
208
+ if (event.Data.MaxRecords > 2000) {
209
+ event.Cancel = true;
210
+ this.showWarning('Max records cannot exceed 2000 in demo mode');
211
+ }
212
+ }
213
+ ```
214
+
215
+ ### Example: Suppress Outlier Clicks
216
+
217
+ ```typescript
218
+ onBeforeClick(event: CancelableEvent<ClusterPoint>): void {
219
+ if (event.Data.ClusterId === -1) {
220
+ event.Cancel = true; // ignore outlier clicks
221
+ }
222
+ }
223
+ ```
224
+
225
+ ### Example: Restrict Zoom Range
226
+
227
+ ```typescript
228
+ onBeforeZoom(event: CancelableEvent<ViewportRect>): void {
229
+ if (event.Data.Width > 5000) {
230
+ event.Cancel = true; // don't allow zooming out too far
231
+ }
232
+ }
233
+ ```
234
+
235
+ ---
236
+
237
+ ## Detail Panel
238
+
239
+ Clicking a data point in the scatter plot opens a slide-in detail panel on the right side. The panel displays:
240
+
241
+ - **Entity icon and record identifier** at the top
242
+ - **Metadata entries** parsed from the vector's stored metadata (key-value pairs)
243
+ - **Cluster membership** showing all other points in the same cluster, clickable to navigate between members
244
+ - **"Open Record" button** that emits the `OpenRecord` event so the host application can navigate to the entity form
245
+
246
+ The detail panel state is managed internally by the scatter component via `SelectedPoint`, `ShowDetailPanel`, `DetailMetadataEntries`, and `ClusterMembers` properties.
247
+
248
+ ### Outputs (Detail Panel)
249
+
250
+ | Output | Payload | Description |
251
+ |---|---|---|
252
+ | `OpenRecord` | `ClusterPoint` | Fires when the user clicks "Open Record" in the detail panel |
253
+
254
+ ### Methods (Detail Panel)
255
+
256
+ | Method | Signature | Description |
257
+ |---|---|---|
258
+ | `CloseDetailPanel` | `(): void` | Programmatically close the detail panel |
259
+ | `OnClusterMemberClick` | `(point: ClusterPoint): void` | Select a different cluster member |
260
+ | `ToggleClusterMembers` | `(): void` | Toggle cluster members list expansion |
261
+
262
+ ---
263
+
264
+ ## LLM-Generated Cluster Labels
265
+
266
+ Cluster labels can be generated using the **"Cluster Naming"** AI prompt. When triggered, the service sends representative metadata from each cluster's members to the LLM, which returns concise, descriptive labels. Labels are displayed:
267
+
268
+ - On the scatter plot as text positioned above cluster centroids
269
+ - In the legend alongside the color swatch
270
+ - In the detail panel's cluster section
271
+
272
+ Labels are stored as `ClusterLabel[]` (with `ClusterId` and `Label` fields) and included when saving a visualization.
273
+
274
+ ---
275
+
276
+ ## Save and Restore Visualizations
277
+
278
+ Visualizations can be saved via the config panel's "Save" action and later restored. A `SavedClusterVisualization` includes:
279
+
280
+ | Field | Description |
281
+ |---|---|
282
+ | `Config` | The `ClusterConfig` used for the run |
283
+ | `Points` | All 2D-projected points |
284
+ | `Clusters` | Cluster summaries |
285
+ | `Metrics` | Clustering quality metrics |
286
+ | `Viewport` | Pan + zoom state (`ViewportRect`) at save time |
287
+ | `ClusterLabels` | LLM-generated (or user-edited) labels |
288
+ | `SavedAt` | Timestamp |
289
+
290
+ When restoring, the scatter component can be initialized with the saved `Points`, `Clusters`, and viewport state without re-running the clustering algorithm.
291
+
292
+ ---
293
+
294
+ ## Entity Document Selector
295
+
296
+ When a selected entity has two or more active entity documents, the config panel displays a document selector dropdown. This allows the user to choose which entity document (and its associated embedding model + vector index) to use for fetching vectors. The parent dashboard uses the `FetchEntityVectors` GraphQL query to retrieve vectors from the vector database filtered by the selected entity document.
297
+
298
+ ---
299
+
300
+ ## Styling and Theming
301
+
302
+ All components use MemberJunction design tokens -- no hardcoded colors. Key tokens in use:
303
+
304
+ | Token | Usage |
305
+ |---|---|
306
+ | `--mj-bg-page` | Scatter container background |
307
+ | `--mj-bg-surface` | Legend background |
308
+ | `--mj-bg-surface-elevated` | Config panel, tooltip |
309
+ | `--mj-bg-surface-hover` | Legend item hover |
310
+ | `--mj-border-default` | Panel/legend borders |
311
+ | `--mj-brand-primary` | Run button, accents |
312
+ | `--mj-text-primary` | Primary text |
313
+ | `--mj-text-secondary` | Labels |
314
+ | `--mj-text-muted` | Captions, muted text |
315
+ | `--mj-status-success` | Good silhouette score |
316
+
317
+ ### Color Palette Override
318
+
319
+ Override cluster colors via the `ColorPalette` input:
320
+
321
+ ```html
322
+ <mj-cluster-scatter
323
+ [ColorPalette]="['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728']">
324
+ </mj-cluster-scatter>
325
+ ```
326
+
327
+ When there are more clusters than colors, the palette wraps around. The default palette (`CLUSTER_COLORS`) provides 10 accessible, distinct colors.
328
+
329
+ ---
330
+
331
+ ## Integration Examples
332
+
333
+ ### Knowledge Hub (Data Explorer)
334
+
335
+ The Knowledge Hub dashboard uses both components inside a `BaseResourceComponent`:
336
+
337
+ ```typescript
338
+ @RegisterClass(BaseResourceComponent, 'ClusterVisualizationResource')
339
+ @Component({ ... })
340
+ export class ClusterVisualizationResourceComponent extends BaseResourceComponent {
341
+ clusteringService = inject(ClusteringService);
342
+ result: ClusterVisualizationResult | null = null;
343
+
344
+ async OnRunClustering(config: ClusterConfig): Promise<void> {
345
+ const vectors = await this.fetchVectorsForEntity(config);
346
+ this.result = await this.clusteringService.RunClustering(vectors, config);
347
+ }
348
+ }
349
+ ```
350
+
351
+ ### Custom Application
352
+
353
+ Use individual components with your own data source:
354
+
355
+ ```typescript
356
+ @Component({
357
+ template: `
358
+ <mj-cluster-scatter
359
+ [Points]="points"
360
+ [Clusters]="clusters"
361
+ [DotRadius]="4"
362
+ [ShowTooltip]="true"
363
+ [TooltipFields]="['Score', 'Category']"
364
+ [EnablePan]="true"
365
+ (BeforePointClick)="validateClick($event)"
366
+ (ClusterSelected)="onClusterPicked($event)">
367
+ </mj-cluster-scatter>
368
+ `
369
+ })
370
+ export class MyVisualizationComponent {
371
+ points: ClusterPoint[] = [];
372
+ clusters: ClusterInfo[] = [];
373
+
374
+ validateClick(event: CancelableEvent<ClusterPoint>): void {
375
+ if (event.Data.Metadata['locked']) {
376
+ event.Cancel = true;
377
+ }
378
+ }
379
+
380
+ onClusterPicked(event: ClusterSelectedEvent): void {
381
+ console.log(`Selected cluster ${event.Label} with ${event.MemberCount} members`);
382
+ }
383
+ }
384
+ ```
385
+
386
+ ### Standalone Service Usage (No UI)
387
+
388
+ Use `ClusteringService` without the Angular components:
389
+
390
+ ```typescript
391
+ const svc = new ClusteringService();
392
+ const result = await svc.RunClustering(myVectors, {
393
+ EntityName: 'Products',
394
+ Algorithm: 'kmeans',
395
+ K: 5,
396
+ Epsilon: 0,
397
+ MinPoints: 0,
398
+ DistanceMetric: 'cosine',
399
+ MaxRecords: 1000,
400
+ Filter: '',
401
+ });
402
+ console.log(`Found ${result.Clusters.length} clusters`);
403
+ ```
404
+
405
+ ---
406
+
407
+ ## Performance Notes
408
+
409
+ | Scenario | Recommendation |
410
+ |---|---|
411
+ | < 500 records | Excellent performance; use UMAP for best quality |
412
+ | 500--2000 records | Good performance; UMAP may take 1--3 seconds |
413
+ | 2000--5000 records | Acceptable; consider PCA fallback for speed |
414
+ | > 5000 records | Set `MaxRecords` to cap at 5000; SVG rendering may lag |
415
+
416
+ ### UMAP vs PCA
417
+
418
+ - **UMAP** preserves local structure (clusters stay tight) but is slower (O(n log n))
419
+ - **PCA** is a fast linear fallback (O(n * d)) that works well for well-separated clusters
420
+ - The service automatically falls back to PCA if UMAP is unavailable or fails
421
+
422
+ ### SVG Rendering
423
+
424
+ - Each point is a `<circle>` element; above ~5000 elements the browser may struggle
425
+ - Selection rings and highlight rings add extra elements per selected point
426
+ - Use `AnimateTransitions = false` for better performance with large datasets
427
+
428
+ ---
429
+
430
+ ## Type Exports
431
+
432
+ All types are exported from the package root:
433
+
434
+ ```typescript
435
+ import {
436
+ // Core data types
437
+ ClusterPoint,
438
+ ClusterInfo,
439
+ ClusterConfig,
440
+ ClusterMetrics,
441
+ ClusterVisualizationResult,
442
+ SavedClusterVisualization,
443
+ ClusterInputVector,
444
+
445
+ // Config panel helper
446
+ ClusterConfigPanelEntityOption,
447
+
448
+ // Event payloads
449
+ CancelableEvent,
450
+ ViewportRect,
451
+ ClusterSelectedEvent,
452
+
453
+ // Constants and factories
454
+ ClusterAlgorithm,
455
+ ClusterDistanceMetric,
456
+ CLUSTER_COLORS,
457
+ DefaultClusterConfig,
458
+ } from '@memberjunction/ng-clustering';
459
+ ```
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=clustering-service.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clustering-service.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/clustering-service.test.ts"],"names":[],"mappings":""}