velo-plot 2.20.0 → 3.0.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/README.md +15 -8
- package/dist/{ChartCore-ivzLqxVb.js → ChartCore-BpzRvN4Y.js} +978 -861
- package/dist/ChartCore-BpzRvN4Y.js.map +1 -0
- package/dist/a11y-Bw6urYpr.js +105 -0
- package/dist/a11y-Bw6urYpr.js.map +1 -0
- package/dist/angular/hooks-entry.d.ts +1 -0
- package/dist/angular/hooks.d.ts +26 -0
- package/dist/angular/index.d.ts +8 -0
- package/dist/angular/velo-plot.component.d.ts +46 -0
- package/dist/angular-hooks.d.ts +1 -0
- package/dist/angular-hooks.js +9 -0
- package/dist/angular-hooks.js.map +1 -0
- package/dist/angular.d.ts +1 -0
- package/dist/angular.js +166 -0
- package/dist/angular.js.map +1 -0
- package/dist/assets/indicator.worker-bv0zC4EX.js.map +1 -1
- package/dist/astro/StackedPlot.astro +19 -0
- package/dist/astro/VeloPlot.astro +23 -0
- package/dist/bindings/shared/a11y.d.ts +26 -0
- package/dist/bindings/shared/chartLifecycle.d.ts +16 -0
- package/dist/bindings/shared/chartSyncBridge.d.ts +8 -0
- package/dist/bindings/shared/dimensions.d.ts +1 -0
- package/dist/bindings/shared/index.d.ts +9 -0
- package/dist/bindings/shared/indicatorBridge.d.ts +11 -0
- package/dist/bindings/shared/optionsSync.d.ts +7 -0
- package/dist/bindings/shared/seriesDiff.d.ts +8 -0
- package/dist/bindings/shared/stackedSync.d.ts +9 -0
- package/dist/bindings/shared/types.d.ts +46 -0
- package/dist/bindings/test-utils/index.d.ts +35 -0
- package/dist/bindings/test-utils/mockLifecycle.d.ts +120 -0
- package/dist/bindings/test-utils/vitestSveltePlugin.d.ts +3 -0
- package/dist/chartSyncBridge-DbWrwtyP.js +57 -0
- package/dist/chartSyncBridge-DbWrwtyP.js.map +1 -0
- package/dist/core/Chart.d.ts +1 -1
- package/dist/core/InteractionManager.d.ts +7 -1
- package/dist/core/OverlayRenderer.d.ts +5 -0
- package/dist/core/annotations/types.d.ts +1 -1
- package/dist/core/chart/ChartCore.d.ts +2 -2
- package/dist/core/chart/types.d.ts +1 -1
- package/dist/core/clipboard/index.d.ts +1 -1
- package/dist/core/debug/index.d.ts +1 -1
- package/dist/core/keybindings/index.d.ts +1 -1
- package/dist/core/loading/index.d.ts +1 -1
- package/dist/core/locale/index.d.ts +1 -1
- package/dist/core/stacked/paneResize.d.ts +3 -0
- package/dist/core/stacked/types.d.ts +10 -0
- package/dist/core/theme-editor/index.d.ts +1 -1
- package/dist/createStackedChart-Dm-YqUT7.js +756 -0
- package/dist/createStackedChart-Dm-YqUT7.js.map +1 -0
- package/dist/examples/PluginDemonstration.d.ts +1 -1
- package/dist/gpuRenderer-BpaMYz-k.js.map +1 -1
- package/dist/hooks-CYPCxoZx.js +69 -0
- package/dist/hooks-CYPCxoZx.js.map +1 -0
- package/dist/{index-BBpJwOct.js → index-0InEyj0q.js} +119 -121
- package/dist/index-0InEyj0q.js.map +1 -0
- package/dist/index-BMiZoKmm.js.map +1 -1
- package/dist/{index-DoYxf1cV.js → index-CWxIHdwX.js} +38 -98
- package/dist/index-CWxIHdwX.js.map +1 -0
- package/dist/index-CaXWSOTk.js.map +1 -1
- package/dist/index-Dag88bW4.js.map +1 -1
- package/dist/index-qhscKTDy.js.map +1 -1
- package/dist/index-qunX30Xu.js.map +1 -1
- package/dist/index-x4stH3jD.js.map +1 -1
- package/dist/{index.core-COREBDNq.js → index.core-BmZe2jRQ.js} +9 -9
- package/dist/index.core-BmZe2jRQ.js.map +1 -0
- package/dist/index.core.d.ts +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/indicators--eJGmVox.js.map +1 -1
- package/dist/{mockDatafeed-927foCM4.js → mockDatafeed-DHIDPcpX.js} +150 -146
- package/dist/mockDatafeed-DHIDPcpX.js.map +1 -0
- package/dist/optionsSync-QUiN4Inw.js +119 -0
- package/dist/optionsSync-QUiN4Inw.js.map +1 -0
- package/dist/plugins/3d/index.d.ts +2 -2
- package/dist/plugins/3d.d.ts +2 -2
- package/dist/plugins/3d.js.map +1 -1
- package/dist/plugins/analysis/index.d.ts +1 -1
- package/dist/plugins/analysis/indicators.d.ts +1 -1
- package/dist/plugins/analysis.d.ts +2 -2
- package/dist/plugins/analysis.js +2 -2
- package/dist/plugins/analysis.js.map +1 -1
- package/dist/plugins/annotations/index.d.ts +1 -1
- package/dist/plugins/annotations.d.ts +2 -2
- package/dist/plugins/annotations.js.map +1 -1
- package/dist/plugins/anomaly-detection.js +1 -1
- package/dist/plugins/anomaly-detection.js.map +1 -1
- package/dist/plugins/broken-axis.d.ts +2 -2
- package/dist/plugins/builtins/crosshair/CrosshairPlugin.d.ts +1 -1
- package/dist/plugins/builtins/index.d.ts +1 -1
- package/dist/plugins/caching.d.ts +2 -2
- package/dist/plugins/clipboard/index.d.ts +2 -2
- package/dist/plugins/clipboard.d.ts +2 -2
- package/dist/plugins/clipboard.js.map +1 -1
- package/dist/plugins/context-menu/index.d.ts +1 -1
- package/dist/plugins/context-menu.d.ts +2 -2
- package/dist/plugins/context-menu.js +1 -1
- package/dist/plugins/context-menu.js.map +1 -1
- package/dist/plugins/data-export/index.d.ts +1 -1
- package/dist/plugins/data-export.d.ts +2 -2
- package/dist/plugins/data-export.js +2 -2
- package/dist/plugins/data-export.js.map +1 -1
- package/dist/plugins/data-transform.d.ts +2 -2
- package/dist/plugins/data-transform.js +19 -19
- package/dist/plugins/data-transform.js.map +1 -1
- package/dist/plugins/debug/index.d.ts +2 -2
- package/dist/plugins/debug.d.ts +2 -2
- package/dist/plugins/debug.js +2 -2
- package/dist/plugins/debug.js.map +1 -1
- package/dist/plugins/forecasting/index.d.ts +1 -1
- package/dist/plugins/forecasting.js.map +1 -1
- package/dist/plugins/gpu/index.d.ts +2 -2
- package/dist/plugins/gpu.d.ts +2 -2
- package/dist/plugins/gpu.js.map +1 -1
- package/dist/plugins/i18n/index.d.ts +2 -2
- package/dist/plugins/i18n.d.ts +2 -2
- package/dist/plugins/i18n.js.map +1 -1
- package/dist/plugins/index.d.ts +1 -1
- package/dist/plugins/keyboard.d.ts +2 -2
- package/dist/plugins/keyboard.js +65 -5
- package/dist/plugins/keyboard.js.map +1 -1
- package/dist/plugins/latex.js.map +1 -1
- package/dist/plugins/lazy-load.d.ts +2 -2
- package/dist/plugins/loading/index.d.ts +1 -1
- package/dist/plugins/loading.d.ts +2 -2
- package/dist/plugins/ml-integration.d.ts +2 -2
- package/dist/plugins/ml-integration.js +5 -5
- package/dist/plugins/ml-integration.js.map +1 -1
- package/dist/plugins/offscreen.d.ts +2 -2
- package/dist/plugins/pattern-recognition.d.ts +2 -2
- package/dist/plugins/pattern-recognition.js +1 -1
- package/dist/plugins/pattern-recognition.js.map +1 -1
- package/dist/plugins/radar.d.ts +2 -2
- package/dist/plugins/regression.d.ts +2 -2
- package/dist/plugins/regression.js +1 -1
- package/dist/plugins/regression.js.map +1 -1
- package/dist/plugins/roi.js +9 -9
- package/dist/plugins/roi.js.map +1 -1
- package/dist/plugins/snapshot/index.d.ts +1 -1
- package/dist/plugins/snapshot/types.d.ts +1 -1
- package/dist/plugins/snapshot.d.ts +2 -2
- package/dist/plugins/snapshot.js.map +1 -1
- package/dist/plugins/streaming/index.d.ts +2 -2
- package/dist/plugins/streaming.d.ts +2 -2
- package/dist/plugins/sync/index.d.ts +3 -2
- package/dist/plugins/sync.d.ts +2 -2
- package/dist/plugins/sync.js.map +1 -1
- package/dist/plugins/theme-editor/index.d.ts +1 -1
- package/dist/plugins/theme-editor.d.ts +2 -2
- package/dist/plugins/tools/index.d.ts +1 -1
- package/dist/plugins/tools/tooltip/index.d.ts +1 -1
- package/dist/plugins/tools.d.ts +2 -2
- package/dist/plugins/types.d.ts +1 -1
- package/dist/plugins/video-recorder.d.ts +2 -2
- package/dist/plugins/virtualization.d.ts +2 -2
- package/dist/plugins/virtualization.js +1 -1
- package/dist/pool-DZ8shSqv.js +109 -0
- package/dist/pool-DZ8shSqv.js.map +1 -0
- package/dist/react/StackedPlot.d.ts +31 -0
- package/dist/react/VeloPlot.d.ts +29 -0
- package/dist/react/index.d.ts +25 -3
- package/dist/react/useChartSync.d.ts +8 -0
- package/dist/react/useIndicator.d.ts +12 -0
- package/dist/react/useVeloPlot.d.ts +19 -0
- package/dist/react.js +328 -24
- package/dist/react.js.map +1 -1
- package/dist/scientific/index.d.ts +48 -0
- package/dist/scientific.d.ts +1 -0
- package/dist/scientific.js +91 -0
- package/dist/scientific.js.map +1 -0
- package/dist/solid/VeloPlot.d.ts +16 -0
- package/dist/solid/index.d.ts +13 -0
- package/dist/solid/useChartSync.d.ts +6 -0
- package/dist/solid/useIndicator.d.ts +11 -0
- package/dist/solid/useStackedPlot.d.ts +14 -0
- package/dist/solid/useVeloPlot.d.ts +18 -0
- package/dist/solid.d.ts +1 -0
- package/dist/solid.js +172 -0
- package/dist/solid.js.map +1 -0
- package/dist/stackedSync-tnrunZMt.js +100 -0
- package/dist/stackedSync-tnrunZMt.js.map +1 -0
- package/dist/svelte/StackedPlot.svelte +29 -0
- package/dist/svelte/StackedPlot.test.ts +114 -0
- package/dist/svelte/VeloPlot.svelte +44 -0
- package/dist/svelte/VeloPlot.test.ts +105 -0
- package/dist/svelte/index.d.ts +11 -0
- package/dist/svelte/index.test.ts +20 -0
- package/dist/svelte/index.ts +15 -0
- package/dist/svelte/useChartSync.d.ts +8 -0
- package/dist/svelte/useChartSync.test.ts +49 -0
- package/dist/svelte/useChartSync.ts +29 -0
- package/dist/svelte/useIndicator.d.ts +13 -0
- package/dist/svelte/useIndicator.test.ts +67 -0
- package/dist/svelte/useIndicator.ts +43 -0
- package/dist/svelte/useStackedPlot.d.ts +16 -0
- package/dist/svelte/useStackedPlot.test.ts +76 -0
- package/dist/svelte/useStackedPlot.ts +54 -0
- package/dist/svelte/useVeloPlot.d.ts +21 -0
- package/dist/svelte/useVeloPlot.test.ts +100 -0
- package/dist/svelte/useVeloPlot.ts +81 -0
- package/dist/svelte.d.ts +1 -0
- package/dist/svelte.js +143 -0
- package/dist/svelte.js.map +1 -0
- package/dist/testing/index.d.ts +1 -1
- package/dist/theme/index.d.ts +2 -1
- package/dist/trading.js +6 -6
- package/dist/types.d.ts +1 -1
- package/dist/{utils-BK5UUXxj.js → utils-Dx0h0bgQ.js} +9 -9
- package/dist/{utils-BK5UUXxj.js.map → utils-Dx0h0bgQ.js.map} +1 -1
- package/dist/velo-plot.full.js +452 -443
- package/dist/velo-plot.full.js.map +1 -1
- package/dist/velo-plot.js +15 -15
- package/dist/vue/StackedPlot.vue.d.ts +48 -0
- package/dist/vue/VeloPlot.vue.d.ts +64 -0
- package/dist/vue/index.d.ts +250 -0
- package/dist/vue/useChartSync.d.ts +52 -0
- package/dist/vue/useIndicator.d.ts +23 -0
- package/dist/vue/useStackedPlot.d.ts +15 -0
- package/dist/vue/useVeloPlot.d.ts +20 -0
- package/dist/vue.d.ts +1 -0
- package/dist/vue.js +312 -0
- package/dist/vue.js.map +1 -0
- package/dist/workers/indicatorsAsync.d.ts +2 -0
- package/dist/workers/pool.d.ts +9 -0
- package/package.json +88 -10
- package/dist/ChartCore-ivzLqxVb.js.map +0 -1
- package/dist/SciPlot-CEU4ApgD.js +0 -463
- package/dist/SciPlot-CEU4ApgD.js.map +0 -1
- package/dist/createStackedChart-DxNW0VkF.js +0 -705
- package/dist/createStackedChart-DxNW0VkF.js.map +0 -1
- package/dist/index-BBpJwOct.js.map +0 -1
- package/dist/index-DoYxf1cV.js.map +0 -1
- package/dist/index.core-COREBDNq.js.map +0 -1
- package/dist/mockDatafeed-927foCM4.js.map +0 -1
- package/dist/pool-15HMCNv8.js +0 -88
- package/dist/pool-15HMCNv8.js.map +0 -1
- package/dist/react/SciPlot.d.ts +0 -60
- package/dist/react/useSciPlot.d.ts +0 -56
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export * from './annotations/index'
|
|
2
|
-
import
|
|
3
|
-
export default
|
|
2
|
+
import VeloPlot from './annotations/index'
|
|
3
|
+
export default VeloPlot
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"annotations.js","sources":["../../src/core/annotations/AnnotationManager.ts","../../src/plugins/annotations/index.ts"],"sourcesContent":["/**\n * AnnotationManager - Manages chart annotations\n * \n * Handles creation, update, removal, and rendering of all annotation types.\n */\n\nimport type { Bounds } from '../../types';\nimport type {\n Annotation,\n HorizontalLineAnnotation,\n VerticalLineAnnotation,\n RectangleAnnotation,\n BandAnnotation,\n TextAnnotation,\n ArrowAnnotation,\n} from './types';\n\n// ============================================\n// Default Styles\n// ============================================\n\nconst DEFAULT_STYLES = {\n line: {\n color: 'rgba(255, 255, 255, 0.7)',\n lineWidth: 1,\n lineDash: [] as number[],\n },\n rectangle: {\n fillColor: 'rgba(100, 100, 255, 0.2)',\n strokeColor: 'rgba(100, 100, 255, 0.5)',\n strokeWidth: 1,\n },\n text: {\n fontSize: 12,\n fontFamily: 'Inter, system-ui, sans-serif',\n color: '#ffffff',\n backgroundColor: 'rgba(0, 0, 0, 0.7)',\n padding: 4,\n },\n arrow: {\n color: 'rgba(255, 255, 255, 0.7)',\n lineWidth: 2,\n headSize: 10,\n },\n};\n\n// ============================================\n// Plot Area Type\n// ============================================\n\nexport interface PlotArea {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n// ============================================\n// AnnotationManager Class\n// ============================================\n\nexport class AnnotationManager {\n private annotations: Map<string, Annotation> = new Map();\n private idCounter = 0;\n\n // ----------------------------------------\n // CRUD Operations\n // ----------------------------------------\n\n /**\n * Add a new annotation\n * @returns The annotation ID\n */\n add(annotation: Annotation): string {\n const id = annotation.id ?? `annotation-${++this.idCounter}`;\n const resolved: Annotation = {\n ...annotation,\n id,\n visible: annotation.visible ?? true,\n interactive: annotation.interactive ?? false,\n zIndex: annotation.zIndex ?? 0,\n };\n\n this.annotations.set(id, resolved);\n return id;\n }\n\n /**\n * Remove an annotation by ID\n */\n remove(id: string): boolean {\n return this.annotations.delete(id);\n }\n\n /**\n * Update an annotation\n */\n update(id: string, updates: Partial<Annotation>): void {\n const existing = this.annotations.get(id);\n if (existing) {\n this.annotations.set(id, { ...existing, ...updates } as Annotation);\n }\n }\n\n /**\n * Get an annotation by ID\n */\n get(id: string): Annotation | undefined {\n return this.annotations.get(id);\n }\n\n /**\n * Get all annotations\n */\n getAll(): Annotation[] {\n return Array.from(this.annotations.values());\n }\n\n /**\n * Clear all annotations\n */\n clear(): void {\n this.annotations.clear();\n }\n\n /**\n * Get count of annotations\n */\n get count(): number {\n return this.annotations.size;\n }\n\n // ----------------------------------------\n // Rendering\n // ----------------------------------------\n\n /**\n * Render all annotations\n */\n render(\n ctx: CanvasRenderingContext2D,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n // Sort by zIndex\n const sorted = this.getAll()\n .filter(a => a.visible !== false)\n .sort((a, b) => (a.zIndex ?? 0) - (b.zIndex ?? 0));\n\n ctx.save();\n\n // Clip to plot area\n ctx.beginPath();\n ctx.rect(plotArea.x, plotArea.y, plotArea.width, plotArea.height);\n ctx.clip();\n\n for (const annotation of sorted) {\n this.renderAnnotation(ctx, annotation, plotArea, bounds, latexAPI);\n }\n\n ctx.restore();\n }\n\n /**\n * Helper to draw text or LaTeX\n */\n private drawLatexOrText(\n ctx: CanvasRenderingContext2D,\n text: string,\n x: number,\n y: number,\n options: {\n fontSize: number;\n fontFamily: string;\n fontWeight?: string | number;\n color: string;\n align?: CanvasTextAlign;\n baseline?: CanvasTextBaseline;\n rotation?: number;\n latex?: boolean;\n },\n latexAPI?: any\n ): void {\n const isLatex = (options.latex || text.includes('\\\\') || text.includes('^') || text.includes('_') || (text.includes('{') && text.includes('}'))) &&\n !!latexAPI && (typeof latexAPI.render === 'function');\n\n if (isLatex) {\n ctx.save();\n ctx.translate(x, y);\n if (options.rotation) ctx.rotate((options.rotation * Math.PI) / 180);\n\n const dims = latexAPI.measure(text, {\n fontSize: options.fontSize,\n fontFamily: options.fontFamily,\n color: options.color\n });\n\n let lx = 0;\n let ly = 0;\n\n // Handle Horizontal Alignment\n const align = options.align ?? \"left\";\n if (align === \"center\") lx = -dims.width / 2;\n else if (align === \"right\") lx = -dims.width;\n\n // Handle Vertical Alignment based on alphabetic baseline of the plugin\n // The plugin draws with textBaseline = 'alphabetic' at the provided y\n const baseline = options.baseline ?? \"alphabetic\";\n if (baseline === \"middle\") {\n ly = -dims.height / 2 + dims.baseline;\n } else if (baseline === \"top\" || baseline === \"hanging\") {\n ly = dims.baseline;\n } else if (baseline === \"bottom\" || baseline === \"ideographic\") {\n ly = -(dims.height - dims.baseline);\n } else {\n // 'alphabetic' or default\n ly = 0;\n }\n\n latexAPI.render(text, ctx, lx, ly, {\n fontSize: options.fontSize,\n fontFamily: options.fontFamily,\n color: options.color\n });\n ctx.restore();\n } else {\n ctx.save();\n ctx.font = `${options.fontWeight ?? ''} ${options.fontSize}px ${options.fontFamily}`;\n ctx.fillStyle = options.color;\n ctx.textAlign = options.align ?? \"left\";\n ctx.textBaseline = options.baseline ?? \"alphabetic\";\n ctx.translate(x, y);\n if (options.rotation) ctx.rotate((options.rotation * Math.PI) / 180);\n ctx.fillText(text, 0, 0);\n ctx.restore();\n }\n }\n\n private renderAnnotation(\n ctx: CanvasRenderingContext2D,\n annotation: Annotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n switch (annotation.type) {\n case 'horizontal-line':\n this.renderHorizontalLine(ctx, annotation, plotArea, bounds, latexAPI);\n break;\n case 'vertical-line':\n this.renderVerticalLine(ctx, annotation, plotArea, bounds, latexAPI);\n break;\n case 'rectangle':\n this.renderRectangle(ctx, annotation, plotArea, bounds, latexAPI);\n break;\n case 'band':\n this.renderBand(ctx, annotation, plotArea, bounds, latexAPI);\n break;\n case 'text':\n this.renderText(ctx, annotation, plotArea, bounds, latexAPI);\n break;\n case 'arrow':\n this.renderArrow(ctx, annotation, plotArea, bounds, latexAPI);\n break;\n }\n }\n\n // ----------------------------------------\n // Coordinate Conversion\n // ----------------------------------------\n\n private dataToPixelX(value: number, bounds: Bounds, plotArea: PlotArea): number {\n const normalized = (value - bounds.xMin) / (bounds.xMax - bounds.xMin);\n return plotArea.x + normalized * plotArea.width;\n }\n\n private dataToPixelY(value: number, bounds: Bounds, plotArea: PlotArea): number {\n const normalized = (value - bounds.yMin) / (bounds.yMax - bounds.yMin);\n return plotArea.y + plotArea.height * (1 - normalized);\n }\n\n // ----------------------------------------\n // Render: Horizontal Line\n // ----------------------------------------\n\n private renderHorizontalLine(\n ctx: CanvasRenderingContext2D,\n annotation: HorizontalLineAnnotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n const y = this.dataToPixelY(annotation.y, bounds, plotArea);\n\n // Skip if outside visible area\n if (y < plotArea.y || y > plotArea.y + plotArea.height) return;\n\n const xStart = annotation.xMin !== undefined\n ? Math.max(this.dataToPixelX(annotation.xMin, bounds, plotArea), plotArea.x)\n : plotArea.x;\n const xEnd = annotation.xMax !== undefined\n ? Math.min(this.dataToPixelX(annotation.xMax, bounds, plotArea), plotArea.x + plotArea.width)\n : plotArea.x + plotArea.width;\n\n ctx.save();\n ctx.strokeStyle = annotation.color ?? DEFAULT_STYLES.line.color;\n ctx.lineWidth = annotation.lineWidth ?? DEFAULT_STYLES.line.lineWidth;\n ctx.setLineDash(annotation.lineDash ?? DEFAULT_STYLES.line.lineDash);\n\n ctx.beginPath();\n ctx.moveTo(xStart, y);\n ctx.lineTo(xEnd, y);\n ctx.stroke();\n\n // Render label if present\n if (annotation.label) {\n this.renderLineLabel(\n ctx,\n annotation.label,\n xStart, xEnd, y,\n annotation.labelPosition ?? 'right',\n 'horizontal',\n annotation.labelBackground,\n latexAPI\n );\n }\n\n ctx.restore();\n }\n\n // ----------------------------------------\n // Render: Vertical Line\n // ----------------------------------------\n\n private renderVerticalLine(\n ctx: CanvasRenderingContext2D,\n annotation: VerticalLineAnnotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n const x = this.dataToPixelX(annotation.x, bounds, plotArea);\n\n // Skip if outside visible area\n if (x < plotArea.x || x > plotArea.x + plotArea.width) return;\n\n const yStart = annotation.yMin !== undefined\n ? Math.min(this.dataToPixelY(annotation.yMin, bounds, plotArea), plotArea.y + plotArea.height)\n : plotArea.y;\n const yEnd = annotation.yMax !== undefined\n ? Math.max(this.dataToPixelY(annotation.yMax, bounds, plotArea), plotArea.y)\n : plotArea.y + plotArea.height;\n\n ctx.save();\n ctx.strokeStyle = annotation.color ?? DEFAULT_STYLES.line.color;\n ctx.lineWidth = annotation.lineWidth ?? DEFAULT_STYLES.line.lineWidth;\n ctx.setLineDash(annotation.lineDash ?? DEFAULT_STYLES.line.lineDash);\n\n ctx.beginPath();\n ctx.moveTo(x, yStart);\n ctx.lineTo(x, yEnd);\n ctx.stroke();\n\n // Render label if present\n if (annotation.label) {\n this.renderLineLabel(\n ctx,\n annotation.label,\n yStart, yEnd, x,\n annotation.labelPosition ?? 'top',\n 'vertical',\n annotation.labelBackground,\n latexAPI\n );\n }\n\n ctx.restore();\n }\n\n // ----------------------------------------\n // Render: Rectangle\n // ----------------------------------------\n\n private renderRectangle(\n ctx: CanvasRenderingContext2D,\n annotation: RectangleAnnotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n const x1 = this.dataToPixelX(annotation.xMin, bounds, plotArea);\n const x2 = this.dataToPixelX(annotation.xMax, bounds, plotArea);\n const y1 = this.dataToPixelY(annotation.yMax, bounds, plotArea); // Note: Y is inverted\n const y2 = this.dataToPixelY(annotation.yMin, bounds, plotArea);\n\n const x = Math.min(x1, x2);\n const y = Math.min(y1, y2);\n const width = Math.abs(x2 - x1);\n const height = Math.abs(y2 - y1);\n\n ctx.save();\n\n // Fill\n if (annotation.fillColor) {\n ctx.fillStyle = annotation.fillColor;\n ctx.fillRect(x, y, width, height);\n }\n\n // Stroke\n if (annotation.strokeColor) {\n ctx.strokeStyle = annotation.strokeColor;\n ctx.lineWidth = annotation.strokeWidth ?? DEFAULT_STYLES.rectangle.strokeWidth;\n ctx.setLineDash(annotation.strokeDash ?? []);\n ctx.strokeRect(x, y, width, height);\n }\n\n // Label\n if (annotation.label) {\n this.renderCenteredLabel(ctx, annotation.label, x + width / 2, y + height / 2, latexAPI);\n }\n\n ctx.restore();\n }\n\n // ----------------------------------------\n // Render: Band\n // ----------------------------------------\n\n private renderBand(\n ctx: CanvasRenderingContext2D,\n annotation: BandAnnotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n // Determine band type and calculate bounds\n let x: number, y: number, width: number, height: number;\n\n if (annotation.xMin !== undefined && annotation.xMax !== undefined) {\n // Vertical band (spans full Y)\n const x1 = this.dataToPixelX(annotation.xMin, bounds, plotArea);\n const x2 = this.dataToPixelX(annotation.xMax, bounds, plotArea);\n x = Math.min(x1, x2);\n width = Math.abs(x2 - x1);\n y = plotArea.y;\n height = plotArea.height;\n\n if (annotation.yMin !== undefined) {\n const yPixel = this.dataToPixelY(annotation.yMin, bounds, plotArea);\n height = yPixel - y;\n }\n if (annotation.yMax !== undefined) {\n const yPixel = this.dataToPixelY(annotation.yMax, bounds, plotArea);\n y = yPixel;\n height = plotArea.y + plotArea.height - y;\n }\n } else if (annotation.yMin !== undefined && annotation.yMax !== undefined) {\n // Horizontal band (spans full X)\n const y1 = this.dataToPixelY(annotation.yMax, bounds, plotArea);\n const y2 = this.dataToPixelY(annotation.yMin, bounds, plotArea);\n y = Math.min(y1, y2);\n height = Math.abs(y2 - y1);\n x = plotArea.x;\n width = plotArea.width;\n } else {\n // Invalid band configuration\n return;\n }\n\n ctx.save();\n\n // Fill\n ctx.fillStyle = annotation.fillColor ?? DEFAULT_STYLES.rectangle.fillColor;\n ctx.fillRect(x, y, width, height);\n\n // Stroke\n if (annotation.strokeColor) {\n ctx.strokeStyle = annotation.strokeColor;\n ctx.lineWidth = annotation.strokeWidth ?? 1;\n ctx.strokeRect(x, y, width, height);\n }\n\n // Label\n if (annotation.label) {\n let labelX = x + width / 2;\n let labelY = y + height / 2;\n\n switch (annotation.labelPosition) {\n case 'top':\n labelY = y + 15;\n break;\n case 'bottom':\n labelY = y + height - 5;\n break;\n case 'left':\n labelX = x + 10;\n break;\n case 'right':\n labelX = x + width - 10;\n break;\n }\n\n this.renderCenteredLabel(ctx, annotation.label, labelX, labelY, latexAPI);\n }\n\n ctx.restore();\n }\n\n // ----------------------------------------\n // Render: Text\n // ----------------------------------------\n\n private renderText(\n ctx: CanvasRenderingContext2D,\n annotation: TextAnnotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n const x = this.dataToPixelX(annotation.x, bounds, plotArea);\n const y = this.dataToPixelY(annotation.y, bounds, plotArea);\n\n ctx.save();\n\n // Apply rotation if specified\n if (annotation.rotation) {\n ctx.translate(x, y);\n ctx.rotate((annotation.rotation * Math.PI) / 180);\n ctx.translate(-x, -y);\n }\n\n const fontSize = annotation.fontSize ?? DEFAULT_STYLES.text.fontSize;\n const fontFamily = annotation.fontFamily ?? DEFAULT_STYLES.text.fontFamily;\n const fontWeight = annotation.fontWeight ?? 'normal';\n const lineHeight = fontSize * 1.2;\n\n ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n\n // Support multi-line text\n const lines = annotation.text.split('\\n');\n const padding = annotation.padding ?? DEFAULT_STYLES.text.padding;\n\n // Measure all lines to find max width\n let maxWidth = 0;\n for (const line of lines) {\n maxWidth = Math.max(maxWidth, ctx.measureText(line).width);\n }\n\n const textWidth = maxWidth + padding * 2;\n const textHeight = (lines.length * lineHeight) - (lineHeight - fontSize) + padding * 2;\n\n // Calculate position based on anchor\n let drawX = x;\n let drawY = y;\n\n switch (annotation.anchor) {\n case 'top-left':\n drawX += textWidth / 2;\n drawY += textHeight / 2;\n break;\n case 'top-right':\n drawX -= textWidth / 2;\n drawY += textHeight / 2;\n break;\n case 'bottom-left':\n drawX += textWidth / 2;\n drawY -= textHeight / 2;\n break;\n case 'bottom-right':\n drawX -= textWidth / 2;\n drawY -= textHeight / 2;\n break;\n case 'top-center':\n drawY += textHeight / 2;\n break;\n case 'bottom-center':\n drawY -= textHeight / 2;\n break;\n case 'left-center':\n drawX += textWidth / 2;\n break;\n case 'right-center':\n drawX -= textWidth / 2;\n break;\n }\n\n // Draw background\n if (annotation.backgroundColor) {\n ctx.fillStyle = annotation.backgroundColor;\n ctx.beginPath();\n ctx.roundRect(\n drawX - textWidth / 2,\n drawY - textHeight / 2,\n textWidth,\n textHeight,\n 4\n );\n ctx.fill();\n }\n\n // Draw text lines\n const color = annotation.color ?? DEFAULT_STYLES.text.color;\n const startY = drawY - (textHeight / 2) + padding + (fontSize / 2);\n\n lines.forEach((line, i) => {\n this.drawLatexOrText(ctx, line, drawX, startY + i * lineHeight, {\n fontSize,\n fontFamily,\n fontWeight,\n color,\n align: 'center',\n baseline: 'middle',\n latex: annotation.latex\n }, latexAPI);\n });\n\n ctx.restore();\n }\n\n // ----------------------------------------\n // Render: Arrow\n // ----------------------------------------\n\n private renderArrow(\n ctx: CanvasRenderingContext2D,\n annotation: ArrowAnnotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n const x1 = this.dataToPixelX(annotation.x1, bounds, plotArea);\n const y1 = this.dataToPixelY(annotation.y1, bounds, plotArea);\n const x2 = this.dataToPixelX(annotation.x2, bounds, plotArea);\n const y2 = this.dataToPixelY(annotation.y2, bounds, plotArea);\n\n ctx.save();\n ctx.strokeStyle = annotation.color ?? DEFAULT_STYLES.arrow.color;\n ctx.fillStyle = annotation.color ?? DEFAULT_STYLES.arrow.color;\n ctx.lineWidth = annotation.lineWidth ?? DEFAULT_STYLES.arrow.lineWidth;\n\n // Draw line\n ctx.beginPath();\n ctx.moveTo(x1, y1);\n ctx.lineTo(x2, y2);\n ctx.stroke();\n\n // Draw arrow head\n const headSize = annotation.headSize ?? DEFAULT_STYLES.arrow.headSize;\n const angle = Math.atan2(y2 - y1, x2 - x1);\n\n const headStyle = annotation.headStyle ?? 'filled';\n\n if (headStyle !== 'none') {\n ctx.beginPath();\n ctx.moveTo(x2, y2);\n ctx.lineTo(\n x2 - headSize * Math.cos(angle - Math.PI / 6),\n y2 - headSize * Math.sin(angle - Math.PI / 6)\n );\n\n if (headStyle === 'filled') {\n ctx.lineTo(\n x2 - headSize * Math.cos(angle + Math.PI / 6),\n y2 - headSize * Math.sin(angle + Math.PI / 6)\n );\n ctx.closePath();\n ctx.fill();\n } else {\n ctx.moveTo(x2, y2);\n ctx.lineTo(\n x2 - headSize * Math.cos(angle + Math.PI / 6),\n y2 - headSize * Math.sin(angle + Math.PI / 6)\n );\n ctx.stroke();\n }\n }\n\n // Draw tail arrow if specified\n if (annotation.showTail) {\n const tailAngle = angle + Math.PI;\n ctx.beginPath();\n ctx.moveTo(x1, y1);\n ctx.lineTo(\n x1 - headSize * Math.cos(tailAngle - Math.PI / 6),\n y1 - headSize * Math.sin(tailAngle - Math.PI / 6)\n );\n ctx.lineTo(\n x1 - headSize * Math.cos(tailAngle + Math.PI / 6),\n y1 - headSize * Math.sin(tailAngle + Math.PI / 6)\n );\n ctx.closePath();\n ctx.fill();\n }\n\n // Draw label if present\n if (annotation.label) {\n const midX = (x1 + x2) / 2;\n const midY = (y1 + y2) / 2;\n this.renderCenteredLabel(ctx, annotation.label, midX, midY - 10, latexAPI);\n }\n\n ctx.restore();\n }\n\n // ----------------------------------------\n // Helper: Render Labels\n // ----------------------------------------\n\n private renderLineLabel(\n ctx: CanvasRenderingContext2D,\n label: string,\n start: number,\n end: number,\n cross: number,\n position: string,\n orientation: 'horizontal' | 'vertical',\n backgroundColor?: string,\n latexAPI?: any\n ): void {\n ctx.save();\n\n ctx.font = `${DEFAULT_STYLES.text.fontSize}px ${DEFAULT_STYLES.text.fontFamily}`;\n const metrics = ctx.measureText(label);\n const padding = 4;\n const textWidth = metrics.width + padding * 2;\n const textHeight = DEFAULT_STYLES.text.fontSize + padding * 2;\n\n let x: number, y: number;\n\n if (orientation === 'horizontal') {\n y = cross;\n\n switch (position) {\n case 'left':\n x = start + 5;\n ctx.textAlign = 'left';\n break;\n case 'right':\n x = end - 5;\n ctx.textAlign = 'right';\n break;\n default:\n x = (start + end) / 2;\n ctx.textAlign = 'center';\n }\n\n ctx.textBaseline = 'bottom';\n y -= 4;\n } else {\n x = cross;\n\n switch (position) {\n case 'top':\n y = start + textHeight;\n break;\n case 'bottom':\n y = end - 5;\n break;\n default:\n y = (start + end) / 2;\n }\n\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n }\n\n // Background\n if (backgroundColor ?? true) {\n ctx.fillStyle = backgroundColor ?? 'rgba(0, 0, 0, 0.7)';\n const bgX = ctx.textAlign === 'left' ? x - padding\n : ctx.textAlign === 'right' ? x - textWidth + padding\n : x - textWidth / 2;\n ctx.fillRect(bgX, y - textHeight + padding, textWidth, textHeight);\n }\n\n // Text\n this.drawLatexOrText(ctx, label, x, y, {\n fontSize: DEFAULT_STYLES.text.fontSize,\n fontFamily: DEFAULT_STYLES.text.fontFamily,\n color: DEFAULT_STYLES.text.color,\n align: ctx.textAlign,\n baseline: ctx.textBaseline,\n }, latexAPI);\n\n ctx.restore();\n }\n\n private renderCenteredLabel(\n ctx: CanvasRenderingContext2D,\n label: string,\n x: number,\n y: number,\n latexAPI?: any\n ): void {\n ctx.save();\n\n ctx.font = `${DEFAULT_STYLES.text.fontSize}px ${DEFAULT_STYLES.text.fontFamily}`;\n const metrics = ctx.measureText(label);\n const padding = 4;\n const textWidth = metrics.width + padding * 2;\n const textHeight = DEFAULT_STYLES.text.fontSize + padding * 2;\n\n // Background\n ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';\n ctx.beginPath();\n ctx.roundRect(x - textWidth / 2, y - textHeight / 2, textWidth, textHeight, 3);\n ctx.fill();\n\n // Text\n this.drawLatexOrText(ctx, label, x, y, {\n fontSize: DEFAULT_STYLES.text.fontSize,\n fontFamily: DEFAULT_STYLES.text.fontFamily,\n color: DEFAULT_STYLES.text.color,\n align: 'center',\n baseline: 'middle',\n }, latexAPI);\n\n ctx.restore();\n }\n}\n","/**\n * Sci Plot - Annotations Plugin\n * \n * Provides annotation capabilities including:\n * - Line, Rectangle, Band, Text, Arrow annotations\n * - Annotation management and rendering\n * \n * @module plugins/annotations\n */\n\nimport { AnnotationManager } from \"../../core/annotations\";\nimport type { Annotation, AnnotationType } from \"../../core/annotations\";\nimport type { PluginManifest, ChartPlugin, PluginContext } from \"../types\";\n\nexport interface PluginAnnotationsConfig {\n /** Default styles for annotations */\n defaultStyles?: Record<string, any>;\n}\n\nconst manifestAnnotations: PluginManifest = {\n name: \"velo-plot-annotations\",\n version: \"1.0.0\",\n description: \"Annotation support for velo-plot\",\n provides: [\"annotation\"],\n tags: [\"annotation\", \"overlay\", \"label\"],\n};\n\n/**\n * SciPlot Annotations Plugin\n * \n * Adds support for drawing lines, shapes, and labels on the chart.\n */\nexport function PluginAnnotations(_config: PluginAnnotationsConfig = {}): ChartPlugin<PluginAnnotationsConfig> {\n let annotationManager: AnnotationManager;\n\n return {\n manifest: manifestAnnotations,\n\n onInit(ctx: PluginContext) {\n annotationManager = new AnnotationManager();\n\n // In a real implementation, we would register this manager in the context\n // so the chart can delegate annotation calls to it.\n // For now, we store it in storage for retrieval.\n ctx.storage.set(\"manager\", annotationManager);\n },\n\n onRenderOverlay(ctx) {\n const plotArea = ctx.render.plotArea;\n const viewBounds = ctx.data.getViewBounds();\n\n // Get LaTeX API if plugin is available\n const latexPlugin = ctx.getPlugin<any>(\"velo-plot-latex\");\n const latexAPI = latexPlugin?.api;\n\n // Render all annotations using the manager and provided contexts\n annotationManager.render(\n ctx.render.ctx2d!,\n plotArea,\n viewBounds,\n latexAPI\n );\n },\n\n onDestroy(_ctx: PluginContext) {\n annotationManager.clear();\n },\n\n api: {\n getManager() {\n return annotationManager;\n },\n add(annotation: Annotation) {\n return annotationManager.add(annotation);\n },\n remove(id: string) {\n return annotationManager.remove(id);\n },\n update(id: string, updates: Partial<Annotation>) {\n return annotationManager.update(id, updates);\n },\n get(id: string) {\n return annotationManager.get(id);\n },\n getAll() {\n return annotationManager.getAll();\n },\n clear() {\n annotationManager.clear();\n }\n }\n };\n}\n\nexport { AnnotationManager };\nexport type { Annotation, AnnotationType };\nexport default PluginAnnotations;\n"],"names":["DEFAULT_STYLES","AnnotationManager","__publicField","annotation","id","resolved","updates","existing","ctx","plotArea","bounds","latexAPI","sorted","a","b","text","x","y","options","dims","lx","ly","align","baseline","value","normalized","xStart","xEnd","yStart","yEnd","x1","x2","y1","y2","width","height","labelX","labelY","fontSize","fontFamily","fontWeight","lineHeight","lines","padding","maxWidth","line","textWidth","textHeight","drawX","drawY","color","startY","i","headSize","angle","headStyle","tailAngle","midX","midY","label","start","end","cross","position","orientation","backgroundColor","metrics","bgX","manifestAnnotations","PluginAnnotations","_config","annotationManager","viewBounds","latexPlugin","_ctx"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"annotations.js","sources":["../../src/core/annotations/AnnotationManager.ts","../../src/plugins/annotations/index.ts"],"sourcesContent":["/**\n * AnnotationManager - Manages chart annotations\n * \n * Handles creation, update, removal, and rendering of all annotation types.\n */\n\nimport type { Bounds } from '../../types';\nimport type {\n Annotation,\n HorizontalLineAnnotation,\n VerticalLineAnnotation,\n RectangleAnnotation,\n BandAnnotation,\n TextAnnotation,\n ArrowAnnotation,\n} from './types';\n\n// ============================================\n// Default Styles\n// ============================================\n\nconst DEFAULT_STYLES = {\n line: {\n color: 'rgba(255, 255, 255, 0.7)',\n lineWidth: 1,\n lineDash: [] as number[],\n },\n rectangle: {\n fillColor: 'rgba(100, 100, 255, 0.2)',\n strokeColor: 'rgba(100, 100, 255, 0.5)',\n strokeWidth: 1,\n },\n text: {\n fontSize: 12,\n fontFamily: 'Inter, system-ui, sans-serif',\n color: '#ffffff',\n backgroundColor: 'rgba(0, 0, 0, 0.7)',\n padding: 4,\n },\n arrow: {\n color: 'rgba(255, 255, 255, 0.7)',\n lineWidth: 2,\n headSize: 10,\n },\n};\n\n// ============================================\n// Plot Area Type\n// ============================================\n\nexport interface PlotArea {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n// ============================================\n// AnnotationManager Class\n// ============================================\n\nexport class AnnotationManager {\n private annotations: Map<string, Annotation> = new Map();\n private idCounter = 0;\n\n // ----------------------------------------\n // CRUD Operations\n // ----------------------------------------\n\n /**\n * Add a new annotation\n * @returns The annotation ID\n */\n add(annotation: Annotation): string {\n const id = annotation.id ?? `annotation-${++this.idCounter}`;\n const resolved: Annotation = {\n ...annotation,\n id,\n visible: annotation.visible ?? true,\n interactive: annotation.interactive ?? false,\n zIndex: annotation.zIndex ?? 0,\n };\n\n this.annotations.set(id, resolved);\n return id;\n }\n\n /**\n * Remove an annotation by ID\n */\n remove(id: string): boolean {\n return this.annotations.delete(id);\n }\n\n /**\n * Update an annotation\n */\n update(id: string, updates: Partial<Annotation>): void {\n const existing = this.annotations.get(id);\n if (existing) {\n this.annotations.set(id, { ...existing, ...updates } as Annotation);\n }\n }\n\n /**\n * Get an annotation by ID\n */\n get(id: string): Annotation | undefined {\n return this.annotations.get(id);\n }\n\n /**\n * Get all annotations\n */\n getAll(): Annotation[] {\n return Array.from(this.annotations.values());\n }\n\n /**\n * Clear all annotations\n */\n clear(): void {\n this.annotations.clear();\n }\n\n /**\n * Get count of annotations\n */\n get count(): number {\n return this.annotations.size;\n }\n\n // ----------------------------------------\n // Rendering\n // ----------------------------------------\n\n /**\n * Render all annotations\n */\n render(\n ctx: CanvasRenderingContext2D,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n // Sort by zIndex\n const sorted = this.getAll()\n .filter(a => a.visible !== false)\n .sort((a, b) => (a.zIndex ?? 0) - (b.zIndex ?? 0));\n\n ctx.save();\n\n // Clip to plot area\n ctx.beginPath();\n ctx.rect(plotArea.x, plotArea.y, plotArea.width, plotArea.height);\n ctx.clip();\n\n for (const annotation of sorted) {\n this.renderAnnotation(ctx, annotation, plotArea, bounds, latexAPI);\n }\n\n ctx.restore();\n }\n\n /**\n * Helper to draw text or LaTeX\n */\n private drawLatexOrText(\n ctx: CanvasRenderingContext2D,\n text: string,\n x: number,\n y: number,\n options: {\n fontSize: number;\n fontFamily: string;\n fontWeight?: string | number;\n color: string;\n align?: CanvasTextAlign;\n baseline?: CanvasTextBaseline;\n rotation?: number;\n latex?: boolean;\n },\n latexAPI?: any\n ): void {\n const isLatex = (options.latex || text.includes('\\\\') || text.includes('^') || text.includes('_') || (text.includes('{') && text.includes('}'))) &&\n !!latexAPI && (typeof latexAPI.render === 'function');\n\n if (isLatex) {\n ctx.save();\n ctx.translate(x, y);\n if (options.rotation) ctx.rotate((options.rotation * Math.PI) / 180);\n\n const dims = latexAPI.measure(text, {\n fontSize: options.fontSize,\n fontFamily: options.fontFamily,\n color: options.color\n });\n\n let lx = 0;\n let ly = 0;\n\n // Handle Horizontal Alignment\n const align = options.align ?? \"left\";\n if (align === \"center\") lx = -dims.width / 2;\n else if (align === \"right\") lx = -dims.width;\n\n // Handle Vertical Alignment based on alphabetic baseline of the plugin\n // The plugin draws with textBaseline = 'alphabetic' at the provided y\n const baseline = options.baseline ?? \"alphabetic\";\n if (baseline === \"middle\") {\n ly = -dims.height / 2 + dims.baseline;\n } else if (baseline === \"top\" || baseline === \"hanging\") {\n ly = dims.baseline;\n } else if (baseline === \"bottom\" || baseline === \"ideographic\") {\n ly = -(dims.height - dims.baseline);\n } else {\n // 'alphabetic' or default\n ly = 0;\n }\n\n latexAPI.render(text, ctx, lx, ly, {\n fontSize: options.fontSize,\n fontFamily: options.fontFamily,\n color: options.color\n });\n ctx.restore();\n } else {\n ctx.save();\n ctx.font = `${options.fontWeight ?? ''} ${options.fontSize}px ${options.fontFamily}`;\n ctx.fillStyle = options.color;\n ctx.textAlign = options.align ?? \"left\";\n ctx.textBaseline = options.baseline ?? \"alphabetic\";\n ctx.translate(x, y);\n if (options.rotation) ctx.rotate((options.rotation * Math.PI) / 180);\n ctx.fillText(text, 0, 0);\n ctx.restore();\n }\n }\n\n private renderAnnotation(\n ctx: CanvasRenderingContext2D,\n annotation: Annotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n switch (annotation.type) {\n case 'horizontal-line':\n this.renderHorizontalLine(ctx, annotation, plotArea, bounds, latexAPI);\n break;\n case 'vertical-line':\n this.renderVerticalLine(ctx, annotation, plotArea, bounds, latexAPI);\n break;\n case 'rectangle':\n this.renderRectangle(ctx, annotation, plotArea, bounds, latexAPI);\n break;\n case 'band':\n this.renderBand(ctx, annotation, plotArea, bounds, latexAPI);\n break;\n case 'text':\n this.renderText(ctx, annotation, plotArea, bounds, latexAPI);\n break;\n case 'arrow':\n this.renderArrow(ctx, annotation, plotArea, bounds, latexAPI);\n break;\n }\n }\n\n // ----------------------------------------\n // Coordinate Conversion\n // ----------------------------------------\n\n private dataToPixelX(value: number, bounds: Bounds, plotArea: PlotArea): number {\n const normalized = (value - bounds.xMin) / (bounds.xMax - bounds.xMin);\n return plotArea.x + normalized * plotArea.width;\n }\n\n private dataToPixelY(value: number, bounds: Bounds, plotArea: PlotArea): number {\n const normalized = (value - bounds.yMin) / (bounds.yMax - bounds.yMin);\n return plotArea.y + plotArea.height * (1 - normalized);\n }\n\n // ----------------------------------------\n // Render: Horizontal Line\n // ----------------------------------------\n\n private renderHorizontalLine(\n ctx: CanvasRenderingContext2D,\n annotation: HorizontalLineAnnotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n const y = this.dataToPixelY(annotation.y, bounds, plotArea);\n\n // Skip if outside visible area\n if (y < plotArea.y || y > plotArea.y + plotArea.height) return;\n\n const xStart = annotation.xMin !== undefined\n ? Math.max(this.dataToPixelX(annotation.xMin, bounds, plotArea), plotArea.x)\n : plotArea.x;\n const xEnd = annotation.xMax !== undefined\n ? Math.min(this.dataToPixelX(annotation.xMax, bounds, plotArea), plotArea.x + plotArea.width)\n : plotArea.x + plotArea.width;\n\n ctx.save();\n ctx.strokeStyle = annotation.color ?? DEFAULT_STYLES.line.color;\n ctx.lineWidth = annotation.lineWidth ?? DEFAULT_STYLES.line.lineWidth;\n ctx.setLineDash(annotation.lineDash ?? DEFAULT_STYLES.line.lineDash);\n\n ctx.beginPath();\n ctx.moveTo(xStart, y);\n ctx.lineTo(xEnd, y);\n ctx.stroke();\n\n // Render label if present\n if (annotation.label) {\n this.renderLineLabel(\n ctx,\n annotation.label,\n xStart, xEnd, y,\n annotation.labelPosition ?? 'right',\n 'horizontal',\n annotation.labelBackground,\n latexAPI\n );\n }\n\n ctx.restore();\n }\n\n // ----------------------------------------\n // Render: Vertical Line\n // ----------------------------------------\n\n private renderVerticalLine(\n ctx: CanvasRenderingContext2D,\n annotation: VerticalLineAnnotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n const x = this.dataToPixelX(annotation.x, bounds, plotArea);\n\n // Skip if outside visible area\n if (x < plotArea.x || x > plotArea.x + plotArea.width) return;\n\n const yStart = annotation.yMin !== undefined\n ? Math.min(this.dataToPixelY(annotation.yMin, bounds, plotArea), plotArea.y + plotArea.height)\n : plotArea.y;\n const yEnd = annotation.yMax !== undefined\n ? Math.max(this.dataToPixelY(annotation.yMax, bounds, plotArea), plotArea.y)\n : plotArea.y + plotArea.height;\n\n ctx.save();\n ctx.strokeStyle = annotation.color ?? DEFAULT_STYLES.line.color;\n ctx.lineWidth = annotation.lineWidth ?? DEFAULT_STYLES.line.lineWidth;\n ctx.setLineDash(annotation.lineDash ?? DEFAULT_STYLES.line.lineDash);\n\n ctx.beginPath();\n ctx.moveTo(x, yStart);\n ctx.lineTo(x, yEnd);\n ctx.stroke();\n\n // Render label if present\n if (annotation.label) {\n this.renderLineLabel(\n ctx,\n annotation.label,\n yStart, yEnd, x,\n annotation.labelPosition ?? 'top',\n 'vertical',\n annotation.labelBackground,\n latexAPI\n );\n }\n\n ctx.restore();\n }\n\n // ----------------------------------------\n // Render: Rectangle\n // ----------------------------------------\n\n private renderRectangle(\n ctx: CanvasRenderingContext2D,\n annotation: RectangleAnnotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n const x1 = this.dataToPixelX(annotation.xMin, bounds, plotArea);\n const x2 = this.dataToPixelX(annotation.xMax, bounds, plotArea);\n const y1 = this.dataToPixelY(annotation.yMax, bounds, plotArea); // Note: Y is inverted\n const y2 = this.dataToPixelY(annotation.yMin, bounds, plotArea);\n\n const x = Math.min(x1, x2);\n const y = Math.min(y1, y2);\n const width = Math.abs(x2 - x1);\n const height = Math.abs(y2 - y1);\n\n ctx.save();\n\n // Fill\n if (annotation.fillColor) {\n ctx.fillStyle = annotation.fillColor;\n ctx.fillRect(x, y, width, height);\n }\n\n // Stroke\n if (annotation.strokeColor) {\n ctx.strokeStyle = annotation.strokeColor;\n ctx.lineWidth = annotation.strokeWidth ?? DEFAULT_STYLES.rectangle.strokeWidth;\n ctx.setLineDash(annotation.strokeDash ?? []);\n ctx.strokeRect(x, y, width, height);\n }\n\n // Label\n if (annotation.label) {\n this.renderCenteredLabel(ctx, annotation.label, x + width / 2, y + height / 2, latexAPI);\n }\n\n ctx.restore();\n }\n\n // ----------------------------------------\n // Render: Band\n // ----------------------------------------\n\n private renderBand(\n ctx: CanvasRenderingContext2D,\n annotation: BandAnnotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n // Determine band type and calculate bounds\n let x: number, y: number, width: number, height: number;\n\n if (annotation.xMin !== undefined && annotation.xMax !== undefined) {\n // Vertical band (spans full Y)\n const x1 = this.dataToPixelX(annotation.xMin, bounds, plotArea);\n const x2 = this.dataToPixelX(annotation.xMax, bounds, plotArea);\n x = Math.min(x1, x2);\n width = Math.abs(x2 - x1);\n y = plotArea.y;\n height = plotArea.height;\n\n if (annotation.yMin !== undefined) {\n const yPixel = this.dataToPixelY(annotation.yMin, bounds, plotArea);\n height = yPixel - y;\n }\n if (annotation.yMax !== undefined) {\n const yPixel = this.dataToPixelY(annotation.yMax, bounds, plotArea);\n y = yPixel;\n height = plotArea.y + plotArea.height - y;\n }\n } else if (annotation.yMin !== undefined && annotation.yMax !== undefined) {\n // Horizontal band (spans full X)\n const y1 = this.dataToPixelY(annotation.yMax, bounds, plotArea);\n const y2 = this.dataToPixelY(annotation.yMin, bounds, plotArea);\n y = Math.min(y1, y2);\n height = Math.abs(y2 - y1);\n x = plotArea.x;\n width = plotArea.width;\n } else {\n // Invalid band configuration\n return;\n }\n\n ctx.save();\n\n // Fill\n ctx.fillStyle = annotation.fillColor ?? DEFAULT_STYLES.rectangle.fillColor;\n ctx.fillRect(x, y, width, height);\n\n // Stroke\n if (annotation.strokeColor) {\n ctx.strokeStyle = annotation.strokeColor;\n ctx.lineWidth = annotation.strokeWidth ?? 1;\n ctx.strokeRect(x, y, width, height);\n }\n\n // Label\n if (annotation.label) {\n let labelX = x + width / 2;\n let labelY = y + height / 2;\n\n switch (annotation.labelPosition) {\n case 'top':\n labelY = y + 15;\n break;\n case 'bottom':\n labelY = y + height - 5;\n break;\n case 'left':\n labelX = x + 10;\n break;\n case 'right':\n labelX = x + width - 10;\n break;\n }\n\n this.renderCenteredLabel(ctx, annotation.label, labelX, labelY, latexAPI);\n }\n\n ctx.restore();\n }\n\n // ----------------------------------------\n // Render: Text\n // ----------------------------------------\n\n private renderText(\n ctx: CanvasRenderingContext2D,\n annotation: TextAnnotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n const x = this.dataToPixelX(annotation.x, bounds, plotArea);\n const y = this.dataToPixelY(annotation.y, bounds, plotArea);\n\n ctx.save();\n\n // Apply rotation if specified\n if (annotation.rotation) {\n ctx.translate(x, y);\n ctx.rotate((annotation.rotation * Math.PI) / 180);\n ctx.translate(-x, -y);\n }\n\n const fontSize = annotation.fontSize ?? DEFAULT_STYLES.text.fontSize;\n const fontFamily = annotation.fontFamily ?? DEFAULT_STYLES.text.fontFamily;\n const fontWeight = annotation.fontWeight ?? 'normal';\n const lineHeight = fontSize * 1.2;\n\n ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n\n // Support multi-line text\n const lines = annotation.text.split('\\n');\n const padding = annotation.padding ?? DEFAULT_STYLES.text.padding;\n\n // Measure all lines to find max width\n let maxWidth = 0;\n for (const line of lines) {\n maxWidth = Math.max(maxWidth, ctx.measureText(line).width);\n }\n\n const textWidth = maxWidth + padding * 2;\n const textHeight = (lines.length * lineHeight) - (lineHeight - fontSize) + padding * 2;\n\n // Calculate position based on anchor\n let drawX = x;\n let drawY = y;\n\n switch (annotation.anchor) {\n case 'top-left':\n drawX += textWidth / 2;\n drawY += textHeight / 2;\n break;\n case 'top-right':\n drawX -= textWidth / 2;\n drawY += textHeight / 2;\n break;\n case 'bottom-left':\n drawX += textWidth / 2;\n drawY -= textHeight / 2;\n break;\n case 'bottom-right':\n drawX -= textWidth / 2;\n drawY -= textHeight / 2;\n break;\n case 'top-center':\n drawY += textHeight / 2;\n break;\n case 'bottom-center':\n drawY -= textHeight / 2;\n break;\n case 'left-center':\n drawX += textWidth / 2;\n break;\n case 'right-center':\n drawX -= textWidth / 2;\n break;\n }\n\n // Draw background\n if (annotation.backgroundColor) {\n ctx.fillStyle = annotation.backgroundColor;\n ctx.beginPath();\n ctx.roundRect(\n drawX - textWidth / 2,\n drawY - textHeight / 2,\n textWidth,\n textHeight,\n 4\n );\n ctx.fill();\n }\n\n // Draw text lines\n const color = annotation.color ?? DEFAULT_STYLES.text.color;\n const startY = drawY - (textHeight / 2) + padding + (fontSize / 2);\n\n lines.forEach((line, i) => {\n this.drawLatexOrText(ctx, line, drawX, startY + i * lineHeight, {\n fontSize,\n fontFamily,\n fontWeight,\n color,\n align: 'center',\n baseline: 'middle',\n latex: annotation.latex\n }, latexAPI);\n });\n\n ctx.restore();\n }\n\n // ----------------------------------------\n // Render: Arrow\n // ----------------------------------------\n\n private renderArrow(\n ctx: CanvasRenderingContext2D,\n annotation: ArrowAnnotation,\n plotArea: PlotArea,\n bounds: Bounds,\n latexAPI?: any\n ): void {\n const x1 = this.dataToPixelX(annotation.x1, bounds, plotArea);\n const y1 = this.dataToPixelY(annotation.y1, bounds, plotArea);\n const x2 = this.dataToPixelX(annotation.x2, bounds, plotArea);\n const y2 = this.dataToPixelY(annotation.y2, bounds, plotArea);\n\n ctx.save();\n ctx.strokeStyle = annotation.color ?? DEFAULT_STYLES.arrow.color;\n ctx.fillStyle = annotation.color ?? DEFAULT_STYLES.arrow.color;\n ctx.lineWidth = annotation.lineWidth ?? DEFAULT_STYLES.arrow.lineWidth;\n\n // Draw line\n ctx.beginPath();\n ctx.moveTo(x1, y1);\n ctx.lineTo(x2, y2);\n ctx.stroke();\n\n // Draw arrow head\n const headSize = annotation.headSize ?? DEFAULT_STYLES.arrow.headSize;\n const angle = Math.atan2(y2 - y1, x2 - x1);\n\n const headStyle = annotation.headStyle ?? 'filled';\n\n if (headStyle !== 'none') {\n ctx.beginPath();\n ctx.moveTo(x2, y2);\n ctx.lineTo(\n x2 - headSize * Math.cos(angle - Math.PI / 6),\n y2 - headSize * Math.sin(angle - Math.PI / 6)\n );\n\n if (headStyle === 'filled') {\n ctx.lineTo(\n x2 - headSize * Math.cos(angle + Math.PI / 6),\n y2 - headSize * Math.sin(angle + Math.PI / 6)\n );\n ctx.closePath();\n ctx.fill();\n } else {\n ctx.moveTo(x2, y2);\n ctx.lineTo(\n x2 - headSize * Math.cos(angle + Math.PI / 6),\n y2 - headSize * Math.sin(angle + Math.PI / 6)\n );\n ctx.stroke();\n }\n }\n\n // Draw tail arrow if specified\n if (annotation.showTail) {\n const tailAngle = angle + Math.PI;\n ctx.beginPath();\n ctx.moveTo(x1, y1);\n ctx.lineTo(\n x1 - headSize * Math.cos(tailAngle - Math.PI / 6),\n y1 - headSize * Math.sin(tailAngle - Math.PI / 6)\n );\n ctx.lineTo(\n x1 - headSize * Math.cos(tailAngle + Math.PI / 6),\n y1 - headSize * Math.sin(tailAngle + Math.PI / 6)\n );\n ctx.closePath();\n ctx.fill();\n }\n\n // Draw label if present\n if (annotation.label) {\n const midX = (x1 + x2) / 2;\n const midY = (y1 + y2) / 2;\n this.renderCenteredLabel(ctx, annotation.label, midX, midY - 10, latexAPI);\n }\n\n ctx.restore();\n }\n\n // ----------------------------------------\n // Helper: Render Labels\n // ----------------------------------------\n\n private renderLineLabel(\n ctx: CanvasRenderingContext2D,\n label: string,\n start: number,\n end: number,\n cross: number,\n position: string,\n orientation: 'horizontal' | 'vertical',\n backgroundColor?: string,\n latexAPI?: any\n ): void {\n ctx.save();\n\n ctx.font = `${DEFAULT_STYLES.text.fontSize}px ${DEFAULT_STYLES.text.fontFamily}`;\n const metrics = ctx.measureText(label);\n const padding = 4;\n const textWidth = metrics.width + padding * 2;\n const textHeight = DEFAULT_STYLES.text.fontSize + padding * 2;\n\n let x: number, y: number;\n\n if (orientation === 'horizontal') {\n y = cross;\n\n switch (position) {\n case 'left':\n x = start + 5;\n ctx.textAlign = 'left';\n break;\n case 'right':\n x = end - 5;\n ctx.textAlign = 'right';\n break;\n default:\n x = (start + end) / 2;\n ctx.textAlign = 'center';\n }\n\n ctx.textBaseline = 'bottom';\n y -= 4;\n } else {\n x = cross;\n\n switch (position) {\n case 'top':\n y = start + textHeight;\n break;\n case 'bottom':\n y = end - 5;\n break;\n default:\n y = (start + end) / 2;\n }\n\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n }\n\n // Background\n if (backgroundColor ?? true) {\n ctx.fillStyle = backgroundColor ?? 'rgba(0, 0, 0, 0.7)';\n const bgX = ctx.textAlign === 'left' ? x - padding\n : ctx.textAlign === 'right' ? x - textWidth + padding\n : x - textWidth / 2;\n ctx.fillRect(bgX, y - textHeight + padding, textWidth, textHeight);\n }\n\n // Text\n this.drawLatexOrText(ctx, label, x, y, {\n fontSize: DEFAULT_STYLES.text.fontSize,\n fontFamily: DEFAULT_STYLES.text.fontFamily,\n color: DEFAULT_STYLES.text.color,\n align: ctx.textAlign,\n baseline: ctx.textBaseline,\n }, latexAPI);\n\n ctx.restore();\n }\n\n private renderCenteredLabel(\n ctx: CanvasRenderingContext2D,\n label: string,\n x: number,\n y: number,\n latexAPI?: any\n ): void {\n ctx.save();\n\n ctx.font = `${DEFAULT_STYLES.text.fontSize}px ${DEFAULT_STYLES.text.fontFamily}`;\n const metrics = ctx.measureText(label);\n const padding = 4;\n const textWidth = metrics.width + padding * 2;\n const textHeight = DEFAULT_STYLES.text.fontSize + padding * 2;\n\n // Background\n ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';\n ctx.beginPath();\n ctx.roundRect(x - textWidth / 2, y - textHeight / 2, textWidth, textHeight, 3);\n ctx.fill();\n\n // Text\n this.drawLatexOrText(ctx, label, x, y, {\n fontSize: DEFAULT_STYLES.text.fontSize,\n fontFamily: DEFAULT_STYLES.text.fontFamily,\n color: DEFAULT_STYLES.text.color,\n align: 'center',\n baseline: 'middle',\n }, latexAPI);\n\n ctx.restore();\n }\n}\n","/**\n * Velo Plot - Annotations Plugin\n * \n * Provides annotation capabilities including:\n * - Line, Rectangle, Band, Text, Arrow annotations\n * - Annotation management and rendering\n * \n * @module plugins/annotations\n */\n\nimport { AnnotationManager } from \"../../core/annotations\";\nimport type { Annotation, AnnotationType } from \"../../core/annotations\";\nimport type { PluginManifest, ChartPlugin, PluginContext } from \"../types\";\n\nexport interface PluginAnnotationsConfig {\n /** Default styles for annotations */\n defaultStyles?: Record<string, any>;\n}\n\nconst manifestAnnotations: PluginManifest = {\n name: \"velo-plot-annotations\",\n version: \"1.0.0\",\n description: \"Annotation support for velo-plot\",\n provides: [\"annotation\"],\n tags: [\"annotation\", \"overlay\", \"label\"],\n};\n\n/**\n * VeloPlot Annotations Plugin\n * \n * Adds support for drawing lines, shapes, and labels on the chart.\n */\nexport function PluginAnnotations(_config: PluginAnnotationsConfig = {}): ChartPlugin<PluginAnnotationsConfig> {\n let annotationManager: AnnotationManager;\n\n return {\n manifest: manifestAnnotations,\n\n onInit(ctx: PluginContext) {\n annotationManager = new AnnotationManager();\n\n // In a real implementation, we would register this manager in the context\n // so the chart can delegate annotation calls to it.\n // For now, we store it in storage for retrieval.\n ctx.storage.set(\"manager\", annotationManager);\n },\n\n onRenderOverlay(ctx) {\n const plotArea = ctx.render.plotArea;\n const viewBounds = ctx.data.getViewBounds();\n\n // Get LaTeX API if plugin is available\n const latexPlugin = ctx.getPlugin<any>(\"velo-plot-latex\");\n const latexAPI = latexPlugin?.api;\n\n // Render all annotations using the manager and provided contexts\n annotationManager.render(\n ctx.render.ctx2d!,\n plotArea,\n viewBounds,\n latexAPI\n );\n },\n\n onDestroy(_ctx: PluginContext) {\n annotationManager.clear();\n },\n\n api: {\n getManager() {\n return annotationManager;\n },\n add(annotation: Annotation) {\n return annotationManager.add(annotation);\n },\n remove(id: string) {\n return annotationManager.remove(id);\n },\n update(id: string, updates: Partial<Annotation>) {\n return annotationManager.update(id, updates);\n },\n get(id: string) {\n return annotationManager.get(id);\n },\n getAll() {\n return annotationManager.getAll();\n },\n clear() {\n annotationManager.clear();\n }\n }\n };\n}\n\nexport { AnnotationManager };\nexport type { Annotation, AnnotationType };\nexport default PluginAnnotations;\n"],"names":["DEFAULT_STYLES","AnnotationManager","__publicField","annotation","id","resolved","updates","existing","ctx","plotArea","bounds","latexAPI","sorted","a","b","text","x","y","options","dims","lx","ly","align","baseline","value","normalized","xStart","xEnd","yStart","yEnd","x1","x2","y1","y2","width","height","labelX","labelY","fontSize","fontFamily","fontWeight","lineHeight","lines","padding","maxWidth","line","textWidth","textHeight","drawX","drawY","color","startY","i","headSize","angle","headStyle","tailAngle","midX","midY","label","start","end","cross","position","orientation","backgroundColor","metrics","bgX","manifestAnnotations","PluginAnnotations","_config","annotationManager","viewBounds","latexPlugin","_ctx"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anomaly-detection.js","sources":["../../src/plugins/anomaly-detection/algorithms.ts","../../src/plugins/anomaly-detection/index.ts"],"sourcesContent":["/**\n * Anomaly Detection Algorithms\n * Each method has distinct characteristics for different use cases\n */\n\nimport type { AnomalyPoint, AnomalyMethod } from './types';\n\n/**\n * Z-Score method: Standard statistical approach\n * - Uses MEAN and STANDARD DEVIATION (parametric)\n * - Assumes normal distribution\n * - Sensitive to extreme outliers\n * - Best for: Clean, normally distributed data\n */\nexport function detectZScore(\n x: Float32Array | Float64Array,\n y: Float32Array | Float64Array,\n threshold: number = 3\n): AnomalyPoint[] {\n const n = y.length;\n if (n < 3) return [];\n \n const anomalies: AnomalyPoint[] = [];\n const windowSize = Math.min(20, Math.floor(n / 10));\n \n for (let i = 0; i < n; i++) {\n const start = Math.max(0, i - windowSize);\n const end = Math.min(n, i + windowSize + 1);\n \n // Calculate local MEAN (parametric - sensitive to outliers)\n let localSum = 0;\n let count = 0;\n for (let j = start; j < end; j++) {\n if (j !== i) {\n localSum += y[j];\n count++;\n }\n }\n const localMean = localSum / count;\n \n // Calculate local STANDARD DEVIATION (parametric)\n let localSumSq = 0;\n for (let j = start; j < end; j++) {\n if (j !== i) {\n localSumSq += Math.pow(y[j] - localMean, 2);\n }\n }\n const localStdDev = Math.sqrt(localSumSq / count);\n \n if (localStdDev === 0) continue;\n \n // Z-score: measures how many standard deviations away from mean\n const zScore = Math.abs((y[i] - localMean) / localStdDev);\n \n if (zScore > threshold) {\n anomalies.push({\n index: i,\n x: x[i],\n y: y[i],\n score: zScore,\n method: 'zscore'\n });\n }\n }\n \n return anomalies;\n}\n\n/**\n * MAD (Median Absolute Deviation) method: Robust statistical approach\n * - Uses MEDIAN instead of mean (non-parametric)\n * - Robust to outliers in the window\n * - Doesn't assume normal distribution\n * - Best for: Data with existing outliers, skewed distributions\n */\nexport function detectMAD(\n x: Float32Array | Float64Array,\n y: Float32Array | Float64Array,\n threshold: number = 3.5\n): AnomalyPoint[] {\n const n = y.length;\n if (n < 3) return [];\n \n const anomalies: AnomalyPoint[] = [];\n const windowSize = Math.min(20, Math.floor(n / 10));\n \n for (let i = 0; i < n; i++) {\n const start = Math.max(0, i - windowSize);\n const end = Math.min(n, i + windowSize + 1);\n \n // Get local window values\n const localValues: number[] = [];\n for (let j = start; j < end; j++) {\n if (j !== i) {\n localValues.push(y[j]);\n }\n }\n \n // Calculate MEDIAN (robust to outliers)\n localValues.sort((a, b) => a - b);\n const localMedian = localValues[Math.floor(localValues.length / 2)];\n \n // Calculate MAD (Median Absolute Deviation - robust measure of spread)\n const deviations = localValues.map(v => Math.abs(v - localMedian));\n deviations.sort((a, b) => a - b);\n const mad = deviations[Math.floor(deviations.length / 2)];\n \n if (mad === 0) continue;\n \n // Modified Z-score using MAD (more robust than standard Z-score)\n // 0.6745 is the consistency constant for normal distribution\n const modifiedZScore = Math.abs((0.6745 * (y[i] - localMedian)) / mad);\n \n if (modifiedZScore > threshold) {\n anomalies.push({\n index: i,\n x: x[i],\n y: y[i],\n score: modifiedZScore,\n method: 'mad'\n });\n }\n }\n \n return anomalies;\n}\n\n/**\n * IQR (Interquartile Range) method: Quartile-based approach\n * - Uses PERCENTILES (25th and 75th)\n * - Classic box-plot outlier detection\n * - Non-parametric, distribution-free\n * - Best for: General purpose, well-understood method\n */\nexport function detectIQR(\n x: Float32Array | Float64Array,\n y: Float32Array | Float64Array,\n multiplier: number = 1.5\n): AnomalyPoint[] {\n const n = y.length;\n if (n < 4) return [];\n \n const anomalies: AnomalyPoint[] = [];\n const windowSize = Math.min(20, Math.floor(n / 10));\n \n for (let i = 0; i < n; i++) {\n const start = Math.max(0, i - windowSize);\n const end = Math.min(n, i + windowSize + 1);\n \n // Get local window values\n const localValues: number[] = [];\n for (let j = start; j < end; j++) {\n if (j !== i) {\n localValues.push(y[j]);\n }\n }\n \n // Calculate QUARTILES (percentile-based)\n localValues.sort((a, b) => a - b);\n const q1Index = Math.floor(localValues.length * 0.25);\n const q3Index = Math.floor(localValues.length * 0.75);\n const q1 = localValues[q1Index];\n const q3 = localValues[q3Index];\n const iqr = q3 - q1;\n \n if (iqr === 0) continue;\n \n // IQR method: points outside [Q1 - k*IQR, Q3 + k*IQR] are outliers\n // k=1.5 for outliers, k=3.0 for extreme outliers\n const lowerBound = q1 - multiplier * iqr;\n const upperBound = q3 + multiplier * iqr;\n \n if (y[i] < lowerBound || y[i] > upperBound) {\n const score = y[i] < lowerBound \n ? (lowerBound - y[i]) / iqr\n : (y[i] - upperBound) / iqr;\n \n anomalies.push({\n index: i,\n x: x[i],\n y: y[i],\n score,\n method: 'iqr'\n });\n }\n }\n \n return anomalies;\n}\n\n/**\n * Simplified Isolation Forest: Detects anomalies using random partitioning\n * - Machine learning approach\n * - Isolates anomalies through random splits\n * - Works well with high-dimensional data\n * - Best for: Complex patterns, unknown distributions\n */\nexport function detectIsolationForest(\n x: Float32Array | Float64Array,\n y: Float32Array | Float64Array,\n contamination: number = 0.05,\n numTrees: number = 10\n): AnomalyPoint[] {\n const n = y.length;\n if (n < 10) return [];\n \n // Calculate anomaly scores for each point\n const scores = new Float32Array(n);\n \n for (let i = 0; i < n; i++) {\n let totalDepth = 0;\n \n // Build multiple trees\n for (let t = 0; t < numTrees; t++) {\n totalDepth += isolationDepth(y, i, 0, 8); // Max depth 8\n }\n \n // Average depth (normalized)\n const avgDepth = totalDepth / numTrees;\n const c = 2 * (Math.log(n - 1) + 0.5772156649) - (2 * (n - 1) / n);\n scores[i] = Math.pow(2, -avgDepth / c);\n }\n \n // Sort scores to find threshold\n const sortedScores = Array.from(scores).sort((a, b) => b - a);\n const thresholdIndex = Math.floor(n * contamination);\n const threshold = sortedScores[thresholdIndex];\n \n // Find anomalies\n const anomalies: AnomalyPoint[] = [];\n for (let i = 0; i < n; i++) {\n if (scores[i] >= threshold) {\n anomalies.push({\n index: i,\n x: x[i],\n y: y[i],\n score: scores[i],\n method: 'isolation-forest'\n });\n }\n }\n \n return anomalies;\n}\n\n/**\n * Helper: Calculate isolation depth for a point\n */\nfunction isolationDepth(\n data: Float32Array | Float64Array,\n pointIndex: number,\n currentDepth: number,\n maxDepth: number\n): number {\n if (currentDepth >= maxDepth) return currentDepth;\n \n // Random split\n const min = Math.min(...Array.from(data));\n const max = Math.max(...Array.from(data));\n const splitValue = min + Math.random() * (max - min);\n \n // Check which side the point falls on\n if (data[pointIndex] < splitValue) {\n return isolationDepth(data, pointIndex, currentDepth + 1, maxDepth);\n } else {\n return isolationDepth(data, pointIndex, currentDepth + 1, maxDepth);\n }\n}\n\n/**\n * Main detection function - routes to appropriate algorithm\n */\nexport function detectAnomalies(\n x: Float32Array | Float64Array,\n y: Float32Array | Float64Array,\n method: AnomalyMethod,\n sensitivity: number\n): AnomalyPoint[] {\n switch (method) {\n case 'zscore':\n return detectZScore(x, y, sensitivity);\n case 'mad':\n return detectMAD(x, y, sensitivity);\n case 'iqr':\n return detectIQR(x, y, sensitivity);\n case 'isolation-forest':\n return detectIsolationForest(x, y, sensitivity);\n default:\n return detectZScore(x, y, sensitivity);\n }\n}\n","/**\n * Anomaly Detection Plugin\n * \n * Detects anomalies in chart data using statistical methods.\n * This is a simplified version that provides the core API.\n * \n * @module plugins/anomaly-detection\n */\n\nimport type { ChartPlugin, PluginContext } from '../types';\nimport type { \n PluginAnomalyDetectionConfig, \n AnomalyDetectionResult\n} from './types';\nimport { detectAnomalies } from './algorithms';\n\nexport type { \n PluginAnomalyDetectionConfig,\n AnomalyDetectionResult,\n AnomalyPoint,\n AnomalyMethod\n} from './types';\n\nconst DEFAULT_CONFIG: Required<PluginAnomalyDetectionConfig> = {\n method: 'zscore',\n sensitivity: 3,\n realtime: false,\n highlight: true,\n highlightColor: '#ff0000',\n highlightSize: 8,\n minWindowSize: 30,\n rollingWindow: false,\n windowSize: 100,\n seriesIds: []\n};\n\nexport const manifestAnomalyDetection = {\n id: 'anomaly-detection',\n name: 'Anomaly Detection',\n version: '1.0.0' as `${number}.${number}.${number}`,\n description: 'Real-time anomaly detection with multiple algorithms',\n author: 'Sci Plot',\n category: 'analysis' as const\n};\n\n/**\n * Anomaly Detection Plugin Factory\n */\nexport function PluginAnomalyDetection(\n userConfig: PluginAnomalyDetectionConfig = {}\n): ChartPlugin<PluginAnomalyDetectionConfig> {\n const config = { ...DEFAULT_CONFIG, ...userConfig };\n let ctx: PluginContext | null = null;\n const detectionResults = new Map<string, AnomalyDetectionResult>();\n \n return {\n manifest: manifestAnomalyDetection,\n \n onInit(pluginCtx: PluginContext) {\n ctx = pluginCtx;\n },\n \n onDestroy() {\n detectionResults.clear();\n ctx = null;\n },\n \n api: {\n /**\n * Run anomaly detection on a specific series\n */\n detect(seriesId: string): AnomalyDetectionResult | null {\n if (!ctx) return null;\n \n const series = ctx.data.getSeries(seriesId);\n if (!series) return null;\n \n const data = series.getData();\n if (!data || data.x.length < config.minWindowSize) return null;\n \n // Use rolling window if enabled\n let x = data.x;\n let y = data.y;\n \n if (config.rollingWindow && data.x.length > config.windowSize) {\n const start = data.x.length - config.windowSize;\n x = data.x.slice(start);\n y = data.y.slice(start);\n }\n \n // Run detection\n const anomalies = detectAnomalies(x, y, config.method, config.sensitivity);\n \n // Store results\n const result: AnomalyDetectionResult = {\n seriesId,\n anomalies,\n totalPoints: y.length,\n method: config.method,\n threshold: config.sensitivity,\n timestamp: Date.now()\n };\n \n detectionResults.set(seriesId, result);\n \n // Emit event\n ctx.events.emit('anomaly:detected', result);\n \n return result;\n },\n \n /**\n * Run detection on all series\n */\n detectAll(): Map<string, AnomalyDetectionResult> {\n if (!ctx) return new Map();\n \n const results = new Map<string, AnomalyDetectionResult>();\n const allSeries = ctx.data.getAllSeries();\n \n allSeries.forEach((_series, seriesId) => {\n const result = (this as any).detect(String(seriesId));\n if (result) {\n results.set(String(seriesId), result);\n }\n });\n \n return results;\n },\n \n /**\n * Get detection results for a specific series\n */\n getResults(seriesId: string): AnomalyDetectionResult | undefined {\n return detectionResults.get(seriesId);\n },\n \n /**\n * Get all detection results\n */\n getAllResults(): Map<string, AnomalyDetectionResult> {\n return new Map(detectionResults);\n },\n \n /**\n * Clear all detection results\n */\n clear(): void {\n detectionResults.clear();\n },\n \n /**\n * Update configuration\n */\n setConfig(newConfig: Partial<PluginAnomalyDetectionConfig>): void {\n Object.assign(config, newConfig);\n },\n \n /**\n * Get current configuration\n */\n getConfig(): PluginAnomalyDetectionConfig {\n return { ...config };\n }\n }\n };\n}\n"],"names":["detectZScore","x","y","threshold","n","anomalies","windowSize","i","start","end","localSum","count","j","localMean","localSumSq","localStdDev","zScore","detectMAD","localValues","a","b","localMedian","deviations","v","mad","modifiedZScore","detectIQR","multiplier","q1Index","q3Index","q1","q3","iqr","lowerBound","upperBound","score","detectIsolationForest","contamination","numTrees","scores","totalDepth","t","isolationDepth","avgDepth","c","sortedScores","thresholdIndex","data","pointIndex","currentDepth","maxDepth","min","max","splitValue","detectAnomalies","method","sensitivity","DEFAULT_CONFIG","manifestAnomalyDetection","PluginAnomalyDetection","userConfig","config","ctx","detectionResults","pluginCtx","seriesId","series","result","results","_series","newConfig"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"anomaly-detection.js","sources":["../../src/plugins/anomaly-detection/algorithms.ts","../../src/plugins/anomaly-detection/index.ts"],"sourcesContent":["/**\n * Anomaly Detection Algorithms\n * Each method has distinct characteristics for different use cases\n */\n\nimport type { AnomalyPoint, AnomalyMethod } from './types';\n\n/**\n * Z-Score method: Standard statistical approach\n * - Uses MEAN and STANDARD DEVIATION (parametric)\n * - Assumes normal distribution\n * - Sensitive to extreme outliers\n * - Best for: Clean, normally distributed data\n */\nexport function detectZScore(\n x: Float32Array | Float64Array,\n y: Float32Array | Float64Array,\n threshold: number = 3\n): AnomalyPoint[] {\n const n = y.length;\n if (n < 3) return [];\n \n const anomalies: AnomalyPoint[] = [];\n const windowSize = Math.min(20, Math.floor(n / 10));\n \n for (let i = 0; i < n; i++) {\n const start = Math.max(0, i - windowSize);\n const end = Math.min(n, i + windowSize + 1);\n \n // Calculate local MEAN (parametric - sensitive to outliers)\n let localSum = 0;\n let count = 0;\n for (let j = start; j < end; j++) {\n if (j !== i) {\n localSum += y[j];\n count++;\n }\n }\n const localMean = localSum / count;\n \n // Calculate local STANDARD DEVIATION (parametric)\n let localSumSq = 0;\n for (let j = start; j < end; j++) {\n if (j !== i) {\n localSumSq += Math.pow(y[j] - localMean, 2);\n }\n }\n const localStdDev = Math.sqrt(localSumSq / count);\n \n if (localStdDev === 0) continue;\n \n // Z-score: measures how many standard deviations away from mean\n const zScore = Math.abs((y[i] - localMean) / localStdDev);\n \n if (zScore > threshold) {\n anomalies.push({\n index: i,\n x: x[i],\n y: y[i],\n score: zScore,\n method: 'zscore'\n });\n }\n }\n \n return anomalies;\n}\n\n/**\n * MAD (Median Absolute Deviation) method: Robust statistical approach\n * - Uses MEDIAN instead of mean (non-parametric)\n * - Robust to outliers in the window\n * - Doesn't assume normal distribution\n * - Best for: Data with existing outliers, skewed distributions\n */\nexport function detectMAD(\n x: Float32Array | Float64Array,\n y: Float32Array | Float64Array,\n threshold: number = 3.5\n): AnomalyPoint[] {\n const n = y.length;\n if (n < 3) return [];\n \n const anomalies: AnomalyPoint[] = [];\n const windowSize = Math.min(20, Math.floor(n / 10));\n \n for (let i = 0; i < n; i++) {\n const start = Math.max(0, i - windowSize);\n const end = Math.min(n, i + windowSize + 1);\n \n // Get local window values\n const localValues: number[] = [];\n for (let j = start; j < end; j++) {\n if (j !== i) {\n localValues.push(y[j]);\n }\n }\n \n // Calculate MEDIAN (robust to outliers)\n localValues.sort((a, b) => a - b);\n const localMedian = localValues[Math.floor(localValues.length / 2)];\n \n // Calculate MAD (Median Absolute Deviation - robust measure of spread)\n const deviations = localValues.map(v => Math.abs(v - localMedian));\n deviations.sort((a, b) => a - b);\n const mad = deviations[Math.floor(deviations.length / 2)];\n \n if (mad === 0) continue;\n \n // Modified Z-score using MAD (more robust than standard Z-score)\n // 0.6745 is the consistency constant for normal distribution\n const modifiedZScore = Math.abs((0.6745 * (y[i] - localMedian)) / mad);\n \n if (modifiedZScore > threshold) {\n anomalies.push({\n index: i,\n x: x[i],\n y: y[i],\n score: modifiedZScore,\n method: 'mad'\n });\n }\n }\n \n return anomalies;\n}\n\n/**\n * IQR (Interquartile Range) method: Quartile-based approach\n * - Uses PERCENTILES (25th and 75th)\n * - Classic box-plot outlier detection\n * - Non-parametric, distribution-free\n * - Best for: General purpose, well-understood method\n */\nexport function detectIQR(\n x: Float32Array | Float64Array,\n y: Float32Array | Float64Array,\n multiplier: number = 1.5\n): AnomalyPoint[] {\n const n = y.length;\n if (n < 4) return [];\n \n const anomalies: AnomalyPoint[] = [];\n const windowSize = Math.min(20, Math.floor(n / 10));\n \n for (let i = 0; i < n; i++) {\n const start = Math.max(0, i - windowSize);\n const end = Math.min(n, i + windowSize + 1);\n \n // Get local window values\n const localValues: number[] = [];\n for (let j = start; j < end; j++) {\n if (j !== i) {\n localValues.push(y[j]);\n }\n }\n \n // Calculate QUARTILES (percentile-based)\n localValues.sort((a, b) => a - b);\n const q1Index = Math.floor(localValues.length * 0.25);\n const q3Index = Math.floor(localValues.length * 0.75);\n const q1 = localValues[q1Index];\n const q3 = localValues[q3Index];\n const iqr = q3 - q1;\n \n if (iqr === 0) continue;\n \n // IQR method: points outside [Q1 - k*IQR, Q3 + k*IQR] are outliers\n // k=1.5 for outliers, k=3.0 for extreme outliers\n const lowerBound = q1 - multiplier * iqr;\n const upperBound = q3 + multiplier * iqr;\n \n if (y[i] < lowerBound || y[i] > upperBound) {\n const score = y[i] < lowerBound \n ? (lowerBound - y[i]) / iqr\n : (y[i] - upperBound) / iqr;\n \n anomalies.push({\n index: i,\n x: x[i],\n y: y[i],\n score,\n method: 'iqr'\n });\n }\n }\n \n return anomalies;\n}\n\n/**\n * Simplified Isolation Forest: Detects anomalies using random partitioning\n * - Machine learning approach\n * - Isolates anomalies through random splits\n * - Works well with high-dimensional data\n * - Best for: Complex patterns, unknown distributions\n */\nexport function detectIsolationForest(\n x: Float32Array | Float64Array,\n y: Float32Array | Float64Array,\n contamination: number = 0.05,\n numTrees: number = 10\n): AnomalyPoint[] {\n const n = y.length;\n if (n < 10) return [];\n \n // Calculate anomaly scores for each point\n const scores = new Float32Array(n);\n \n for (let i = 0; i < n; i++) {\n let totalDepth = 0;\n \n // Build multiple trees\n for (let t = 0; t < numTrees; t++) {\n totalDepth += isolationDepth(y, i, 0, 8); // Max depth 8\n }\n \n // Average depth (normalized)\n const avgDepth = totalDepth / numTrees;\n const c = 2 * (Math.log(n - 1) + 0.5772156649) - (2 * (n - 1) / n);\n scores[i] = Math.pow(2, -avgDepth / c);\n }\n \n // Sort scores to find threshold\n const sortedScores = Array.from(scores).sort((a, b) => b - a);\n const thresholdIndex = Math.floor(n * contamination);\n const threshold = sortedScores[thresholdIndex];\n \n // Find anomalies\n const anomalies: AnomalyPoint[] = [];\n for (let i = 0; i < n; i++) {\n if (scores[i] >= threshold) {\n anomalies.push({\n index: i,\n x: x[i],\n y: y[i],\n score: scores[i],\n method: 'isolation-forest'\n });\n }\n }\n \n return anomalies;\n}\n\n/**\n * Helper: Calculate isolation depth for a point\n */\nfunction isolationDepth(\n data: Float32Array | Float64Array,\n pointIndex: number,\n currentDepth: number,\n maxDepth: number\n): number {\n if (currentDepth >= maxDepth) return currentDepth;\n \n // Random split\n const min = Math.min(...Array.from(data));\n const max = Math.max(...Array.from(data));\n const splitValue = min + Math.random() * (max - min);\n \n // Check which side the point falls on\n if (data[pointIndex] < splitValue) {\n return isolationDepth(data, pointIndex, currentDepth + 1, maxDepth);\n } else {\n return isolationDepth(data, pointIndex, currentDepth + 1, maxDepth);\n }\n}\n\n/**\n * Main detection function - routes to appropriate algorithm\n */\nexport function detectAnomalies(\n x: Float32Array | Float64Array,\n y: Float32Array | Float64Array,\n method: AnomalyMethod,\n sensitivity: number\n): AnomalyPoint[] {\n switch (method) {\n case 'zscore':\n return detectZScore(x, y, sensitivity);\n case 'mad':\n return detectMAD(x, y, sensitivity);\n case 'iqr':\n return detectIQR(x, y, sensitivity);\n case 'isolation-forest':\n return detectIsolationForest(x, y, sensitivity);\n default:\n return detectZScore(x, y, sensitivity);\n }\n}\n","/**\n * Anomaly Detection Plugin\n * \n * Detects anomalies in chart data using statistical methods.\n * This is a simplified version that provides the core API.\n * \n * @module plugins/anomaly-detection\n */\n\nimport type { ChartPlugin, PluginContext } from '../types';\nimport type { \n PluginAnomalyDetectionConfig, \n AnomalyDetectionResult\n} from './types';\nimport { detectAnomalies } from './algorithms';\n\nexport type { \n PluginAnomalyDetectionConfig,\n AnomalyDetectionResult,\n AnomalyPoint,\n AnomalyMethod\n} from './types';\n\nconst DEFAULT_CONFIG: Required<PluginAnomalyDetectionConfig> = {\n method: 'zscore',\n sensitivity: 3,\n realtime: false,\n highlight: true,\n highlightColor: '#ff0000',\n highlightSize: 8,\n minWindowSize: 30,\n rollingWindow: false,\n windowSize: 100,\n seriesIds: []\n};\n\nexport const manifestAnomalyDetection = {\n id: 'anomaly-detection',\n name: 'Anomaly Detection',\n version: '1.0.0' as `${number}.${number}.${number}`,\n description: 'Real-time anomaly detection with multiple algorithms',\n author: 'Velo Plot',\n category: 'analysis' as const\n};\n\n/**\n * Anomaly Detection Plugin Factory\n */\nexport function PluginAnomalyDetection(\n userConfig: PluginAnomalyDetectionConfig = {}\n): ChartPlugin<PluginAnomalyDetectionConfig> {\n const config = { ...DEFAULT_CONFIG, ...userConfig };\n let ctx: PluginContext | null = null;\n const detectionResults = new Map<string, AnomalyDetectionResult>();\n \n return {\n manifest: manifestAnomalyDetection,\n \n onInit(pluginCtx: PluginContext) {\n ctx = pluginCtx;\n },\n \n onDestroy() {\n detectionResults.clear();\n ctx = null;\n },\n \n api: {\n /**\n * Run anomaly detection on a specific series\n */\n detect(seriesId: string): AnomalyDetectionResult | null {\n if (!ctx) return null;\n \n const series = ctx.data.getSeries(seriesId);\n if (!series) return null;\n \n const data = series.getData();\n if (!data || data.x.length < config.minWindowSize) return null;\n \n // Use rolling window if enabled\n let x = data.x;\n let y = data.y;\n \n if (config.rollingWindow && data.x.length > config.windowSize) {\n const start = data.x.length - config.windowSize;\n x = data.x.slice(start);\n y = data.y.slice(start);\n }\n \n // Run detection\n const anomalies = detectAnomalies(x, y, config.method, config.sensitivity);\n \n // Store results\n const result: AnomalyDetectionResult = {\n seriesId,\n anomalies,\n totalPoints: y.length,\n method: config.method,\n threshold: config.sensitivity,\n timestamp: Date.now()\n };\n \n detectionResults.set(seriesId, result);\n \n // Emit event\n ctx.events.emit('anomaly:detected', result);\n \n return result;\n },\n \n /**\n * Run detection on all series\n */\n detectAll(): Map<string, AnomalyDetectionResult> {\n if (!ctx) return new Map();\n \n const results = new Map<string, AnomalyDetectionResult>();\n const allSeries = ctx.data.getAllSeries();\n \n allSeries.forEach((_series, seriesId) => {\n const result = (this as any).detect(String(seriesId));\n if (result) {\n results.set(String(seriesId), result);\n }\n });\n \n return results;\n },\n \n /**\n * Get detection results for a specific series\n */\n getResults(seriesId: string): AnomalyDetectionResult | undefined {\n return detectionResults.get(seriesId);\n },\n \n /**\n * Get all detection results\n */\n getAllResults(): Map<string, AnomalyDetectionResult> {\n return new Map(detectionResults);\n },\n \n /**\n * Clear all detection results\n */\n clear(): void {\n detectionResults.clear();\n },\n \n /**\n * Update configuration\n */\n setConfig(newConfig: Partial<PluginAnomalyDetectionConfig>): void {\n Object.assign(config, newConfig);\n },\n \n /**\n * Get current configuration\n */\n getConfig(): PluginAnomalyDetectionConfig {\n return { ...config };\n }\n }\n };\n}\n"],"names":["detectZScore","x","y","threshold","n","anomalies","windowSize","i","start","end","localSum","count","j","localMean","localSumSq","localStdDev","zScore","detectMAD","localValues","a","b","localMedian","deviations","v","mad","modifiedZScore","detectIQR","multiplier","q1Index","q3Index","q1","q3","iqr","lowerBound","upperBound","score","detectIsolationForest","contamination","numTrees","scores","totalDepth","t","isolationDepth","avgDepth","c","sortedScores","thresholdIndex","data","pointIndex","currentDepth","maxDepth","min","max","splitValue","detectAnomalies","method","sensitivity","DEFAULT_CONFIG","manifestAnomalyDetection","PluginAnomalyDetection","userConfig","config","ctx","detectionResults","pluginCtx","seriesId","series","result","results","_series","newConfig"],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export * from './broken-axis/index'
|
|
2
|
-
import
|
|
3
|
-
export default
|
|
2
|
+
import VeloPlot from './broken-axis/index'
|
|
3
|
+
export default VeloPlot
|
|
@@ -12,7 +12,7 @@ export interface CrosshairPluginConfig {
|
|
|
12
12
|
/** Line width (default: 1) */
|
|
13
13
|
lineWidth?: number;
|
|
14
14
|
/**
|
|
15
|
-
* @deprecated Use valueDisplayMode instead
|
|
15
|
+
* @deprecated Use valueDisplayMode instead. **Removed in v4.0.**
|
|
16
16
|
* Show axis labels (will be converted to valueDisplayMode)
|
|
17
17
|
*/
|
|
18
18
|
showAxisLabels?: boolean;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export * from './caching/index'
|
|
2
|
-
import
|
|
3
|
-
export default
|
|
2
|
+
import VeloPlot from './caching/index'
|
|
3
|
+
export default VeloPlot
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ChartPlugin } from '../types';
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* VeloPlot Engine - Clipboard Plugin
|
|
4
4
|
*
|
|
5
5
|
* Provides clipboard integration for copying chart data and images.
|
|
6
6
|
*
|
|
@@ -12,7 +12,7 @@ export interface PluginClipboardConfig {
|
|
|
12
12
|
defaultFormat?: string;
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
15
|
+
* VeloPlot Clipboard Plugin
|
|
16
16
|
*
|
|
17
17
|
* Adds support for copying data and screenshots to the clipboard.
|
|
18
18
|
*/
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export * from './clipboard/index'
|
|
2
|
-
import
|
|
3
|
-
export default
|
|
2
|
+
import VeloPlot from './clipboard/index'
|
|
3
|
+
export default VeloPlot
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clipboard.js","sources":["../../src/core/clipboard/index.ts","../../src/plugins/clipboard/index.ts"],"sourcesContent":["/**\n * Sci Plot - Clipboard Module\n * \n * Provides clipboard operations for copying chart data to various formats.\n * Supports copying selected points, visible data, or all data.\n * \n * @module clipboard\n */\n\n// ============================================\n// Types\n// ============================================\n\nexport type ClipboardFormat = 'tsv' | 'csv' | 'json' | 'markdown';\n\nexport interface ClipboardOptions {\n /** Output format (default: 'tsv' - Excel compatible) */\n format?: ClipboardFormat;\n /** Include column headers (default: true) */\n includeHeaders?: boolean;\n /** Decimal precision (default: 6) */\n precision?: number;\n /** Use scientific notation for very large/small numbers (default: true) */\n scientific?: boolean;\n /** Scientific notation threshold (default: 1e6) */\n scientificThreshold?: number;\n /** Custom column separator (overrides format default) */\n separator?: string;\n /** Custom line separator (default: '\\n') */\n lineSeparator?: string;\n /** Include series name in output (default: true for multi-series) */\n includeSeriesName?: boolean;\n /** Custom header names */\n headers?: {\n x?: string;\n y?: string;\n series?: string;\n };\n}\n\nexport interface ClipboardDataPoint {\n x: number;\n y: number;\n seriesId?: string;\n seriesName?: string;\n index?: number;\n}\n\nexport interface ClipboardResult {\n /** Whether the copy was successful */\n success: boolean;\n /** Number of points copied */\n pointCount: number;\n /** Number of series included */\n seriesCount: number;\n /** The formatted text that was copied */\n text?: string;\n /** Error message if failed */\n error?: string;\n}\n\n// ============================================\n// Format Helpers\n// ============================================\n\nconst FORMAT_CONFIGS: Record<ClipboardFormat, { separator: string; quote: boolean; extension: string }> = {\n tsv: { separator: '\\t', quote: false, extension: 'tsv' },\n csv: { separator: ',', quote: true, extension: 'csv' },\n json: { separator: '', quote: false, extension: 'json' },\n markdown: { separator: ' | ', quote: false, extension: 'md' },\n};\n\n// ============================================\n// Clipboard Manager\n// ============================================\n\nexport class ClipboardManager {\n private defaultOptions: ClipboardOptions = {\n format: 'tsv',\n includeHeaders: true,\n precision: 6,\n scientific: true,\n scientificThreshold: 1e6,\n lineSeparator: '\\n',\n includeSeriesName: false,\n };\n\n constructor(options?: Partial<ClipboardOptions>) {\n if (options) {\n this.defaultOptions = { ...this.defaultOptions, ...options };\n }\n }\n\n /**\n * Copy data points to clipboard\n */\n async copyPoints(\n points: ClipboardDataPoint[],\n options?: Partial<ClipboardOptions>\n ): Promise<ClipboardResult> {\n const opts = { ...this.defaultOptions, ...options };\n \n if (!points || points.length === 0) {\n return {\n success: false,\n pointCount: 0,\n seriesCount: 0,\n error: 'No data points to copy',\n };\n }\n\n try {\n const text = this.formatPoints(points, opts);\n await this.writeToClipboard(text);\n\n const seriesIds = new Set(points.map(p => p.seriesId).filter(Boolean));\n \n return {\n success: true,\n pointCount: points.length,\n seriesCount: seriesIds.size || 1,\n text,\n };\n } catch (error) {\n return {\n success: false,\n pointCount: 0,\n seriesCount: 0,\n error: error instanceof Error ? error.message : 'Failed to copy to clipboard',\n };\n }\n }\n\n /**\n * Copy series data to clipboard\n */\n async copySeries(\n seriesData: { id: string; name?: string; x: Float32Array | Float64Array; y: Float32Array | Float64Array }[],\n options?: Partial<ClipboardOptions>\n ): Promise<ClipboardResult> {\n const points: ClipboardDataPoint[] = [];\n \n for (const series of seriesData) {\n for (let i = 0; i < series.x.length; i++) {\n points.push({\n x: series.x[i],\n y: series.y[i],\n seriesId: series.id,\n seriesName: series.name || series.id,\n index: i,\n });\n }\n }\n\n // Enable series name if multiple series\n const opts = { ...options };\n if (seriesData.length > 1 && opts.includeSeriesName === undefined) {\n opts.includeSeriesName = true;\n }\n\n return this.copyPoints(points, opts);\n }\n\n /**\n * Format data points to string\n */\n formatPoints(points: ClipboardDataPoint[], options: ClipboardOptions): string {\n const format = options.format || 'tsv';\n \n if (format === 'json') {\n return this.formatAsJson(points, options);\n }\n \n if (format === 'markdown') {\n return this.formatAsMarkdown(points, options);\n }\n\n return this.formatAsDelimited(points, options);\n }\n\n /**\n * Format as delimited text (TSV/CSV)\n */\n private formatAsDelimited(points: ClipboardDataPoint[], options: ClipboardOptions): string {\n const format = options.format || 'tsv';\n const config = FORMAT_CONFIGS[format];\n const separator = options.separator || config.separator;\n const lineSeparator = options.lineSeparator || '\\n';\n const lines: string[] = [];\n\n // Headers\n if (options.includeHeaders) {\n const headerParts: string[] = [];\n if (options.includeSeriesName) {\n headerParts.push(options.headers?.series || 'Series');\n }\n headerParts.push(options.headers?.x || 'X');\n headerParts.push(options.headers?.y || 'Y');\n lines.push(headerParts.join(separator));\n }\n\n // Data rows\n for (const point of points) {\n const rowParts: string[] = [];\n \n if (options.includeSeriesName) {\n const seriesName = point.seriesName || point.seriesId || '';\n rowParts.push(config.quote ? `\"${seriesName}\"` : seriesName);\n }\n \n rowParts.push(this.formatNumber(point.x, options));\n rowParts.push(this.formatNumber(point.y, options));\n \n lines.push(rowParts.join(separator));\n }\n\n return lines.join(lineSeparator);\n }\n\n /**\n * Format as JSON\n */\n private formatAsJson(points: ClipboardDataPoint[], options: ClipboardOptions): string {\n const data = points.map(p => {\n const obj: Record<string, unknown> = {\n x: this.roundNumber(p.x, options.precision || 6),\n y: this.roundNumber(p.y, options.precision || 6),\n };\n if (options.includeSeriesName && p.seriesId) {\n obj.series = p.seriesName || p.seriesId;\n }\n return obj;\n });\n\n return JSON.stringify(data, null, 2);\n }\n\n /**\n * Format as Markdown table\n */\n private formatAsMarkdown(points: ClipboardDataPoint[], options: ClipboardOptions): string {\n const lines: string[] = [];\n const separator = ' | ';\n\n // Header\n const headerParts: string[] = [];\n if (options.includeSeriesName) {\n headerParts.push(options.headers?.series || 'Series');\n }\n headerParts.push(options.headers?.x || 'X');\n headerParts.push(options.headers?.y || 'Y');\n \n lines.push('| ' + headerParts.join(separator) + ' |');\n \n // Separator row\n const sepRow = headerParts.map(() => '---');\n lines.push('| ' + sepRow.join(separator) + ' |');\n\n // Data rows\n for (const point of points) {\n const rowParts: string[] = [];\n \n if (options.includeSeriesName) {\n rowParts.push(point.seriesName || point.seriesId || '');\n }\n \n rowParts.push(this.formatNumber(point.x, options));\n rowParts.push(this.formatNumber(point.y, options));\n \n lines.push('| ' + rowParts.join(separator) + ' |');\n }\n\n return lines.join('\\n');\n }\n\n /**\n * Format a number for output\n */\n private formatNumber(value: number, options: ClipboardOptions): string {\n const precision = options.precision ?? 6;\n const threshold = options.scientificThreshold ?? 1e6;\n\n if (!isFinite(value)) {\n return value.toString();\n }\n\n // Use scientific notation for very large or very small numbers\n if (options.scientific && (Math.abs(value) >= threshold || (Math.abs(value) < 1e-4 && value !== 0))) {\n return value.toExponential(precision);\n }\n\n return this.roundNumber(value, precision).toString();\n }\n\n /**\n * Round a number to specified precision\n */\n private roundNumber(value: number, precision: number): number {\n const factor = Math.pow(10, precision);\n return Math.round(value * factor) / factor;\n }\n\n /**\n * Write text to system clipboard\n */\n private async writeToClipboard(text: string): Promise<void> {\n if (navigator.clipboard && navigator.clipboard.writeText) {\n await navigator.clipboard.writeText(text);\n } else {\n // Fallback for older browsers\n this.fallbackCopyToClipboard(text);\n }\n }\n\n /**\n * Fallback clipboard copy using hidden textarea\n */\n private fallbackCopyToClipboard(text: string): void {\n const textarea = document.createElement('textarea');\n textarea.value = text;\n textarea.style.position = 'fixed';\n textarea.style.left = '-9999px';\n textarea.style.top = '-9999px';\n document.body.appendChild(textarea);\n textarea.focus();\n textarea.select();\n \n try {\n document.execCommand('copy');\n } finally {\n document.body.removeChild(textarea);\n }\n }\n\n /**\n * Read from clipboard (for paste functionality)\n */\n async readFromClipboard(): Promise<string | null> {\n if (navigator.clipboard && navigator.clipboard.readText) {\n try {\n return await navigator.clipboard.readText();\n } catch {\n return null;\n }\n }\n return null;\n }\n\n /**\n * Parse clipboard text to data points\n */\n parseClipboardData(text: string, format?: ClipboardFormat): ClipboardDataPoint[] {\n const points: ClipboardDataPoint[] = [];\n \n // Try to detect format\n const detectedFormat = format || this.detectFormat(text);\n \n if (detectedFormat === 'json') {\n return this.parseJson(text);\n }\n\n // Parse as delimited\n const lines = text.trim().split(/\\r?\\n/);\n const separator = detectedFormat === 'csv' ? ',' : detectedFormat === 'tsv' ? '\\t' : ',';\n \n // Skip header if present\n const hasHeader = lines.length > 0 && /^[a-zA-Z]/.test(lines[0].trim());\n const startIndex = hasHeader ? 1 : 0;\n\n for (let i = startIndex; i < lines.length; i++) {\n const parts = lines[i].split(separator).map(p => p.trim().replace(/^\"|\"$/g, ''));\n \n if (parts.length >= 2) {\n const x = parseFloat(parts[0]);\n const y = parseFloat(parts[1]);\n \n if (!isNaN(x) && !isNaN(y)) {\n points.push({ x, y, index: i - startIndex });\n }\n }\n }\n\n return points;\n }\n\n /**\n * Detect format from text content\n */\n private detectFormat(text: string): ClipboardFormat {\n const trimmed = text.trim();\n \n if (trimmed.startsWith('[') || trimmed.startsWith('{')) {\n return 'json';\n }\n \n if (trimmed.includes('\\t')) {\n return 'tsv';\n }\n \n if (trimmed.includes(' | ')) {\n return 'markdown';\n }\n \n return 'csv';\n }\n\n /**\n * Parse JSON data\n */\n private parseJson(text: string): ClipboardDataPoint[] {\n try {\n const data = JSON.parse(text);\n const points: ClipboardDataPoint[] = [];\n const items = Array.isArray(data) ? data : [data];\n \n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n if (typeof item.x === 'number' && typeof item.y === 'number') {\n points.push({\n x: item.x,\n y: item.y,\n seriesId: item.series || item.seriesId,\n seriesName: item.seriesName || item.series,\n index: i,\n });\n }\n }\n \n return points;\n } catch {\n return [];\n }\n }\n\n /**\n * Set default options\n */\n setDefaults(options: Partial<ClipboardOptions>): void {\n this.defaultOptions = { ...this.defaultOptions, ...options };\n }\n\n /**\n * Get current default options\n */\n getDefaults(): ClipboardOptions {\n return { ...this.defaultOptions };\n }\n}\n\n// ============================================\n// Convenience Functions\n// ============================================\n\n/** Singleton instance for global use */\nlet globalClipboardManager: ClipboardManager | null = null;\n\n/**\n * Get the global clipboard manager instance\n */\nexport function getClipboardManager(): ClipboardManager {\n if (!globalClipboardManager) {\n globalClipboardManager = new ClipboardManager();\n }\n return globalClipboardManager;\n}\n\n/**\n * Copy data points to clipboard (convenience function)\n */\nexport async function copyToClipboard(\n points: ClipboardDataPoint[],\n options?: Partial<ClipboardOptions>\n): Promise<ClipboardResult> {\n return getClipboardManager().copyPoints(points, options);\n}\n\n/**\n * Format data as delimited string (without copying)\n */\nexport function formatData(\n points: ClipboardDataPoint[],\n options?: Partial<ClipboardOptions>\n): string {\n const manager = getClipboardManager();\n return manager.formatPoints(points, { ...manager.getDefaults(), ...options });\n}\n","/**\n * SciPlot Engine - Clipboard Plugin\n * \n * Provides clipboard integration for copying chart data and images.\n * \n * @module plugins/clipboard\n */\n\nexport * from \"../../core/clipboard\";\n\nimport type { PluginManifest, ChartPlugin, PluginContext } from \"../types\";\n\nexport interface PluginClipboardConfig {\n /** Default format for copied data: 'csv' | 'json' | 'image' */\n defaultFormat?: string;\n}\n\nconst manifestClipboard: PluginManifest = {\n name: \"velo-plot-clipboard\",\n version: \"1.0.0\",\n description: \"Clipboard integration for velo-plot\",\n provides: [\"interaction\"],\n tags: [\"clipboard\", \"copy\", \"paste\", \"export\"],\n};\n\n/**\n * SciPlot Clipboard Plugin\n * \n * Adds support for copying data and screenshots to the clipboard.\n */\nexport function PluginClipboard(_config: PluginClipboardConfig = {}): ChartPlugin<PluginClipboardConfig> {\n return {\n manifest: manifestClipboard,\n\n onInit(_ctx: PluginContext) {\n },\n\n onDestroy(_ctx: PluginContext) {\n },\n\n api: {\n copyCurrentView() {\n // Implementation would call copyToClipboard with data from current view\n }\n }\n };\n}\n\nexport default PluginClipboard;\n"],"names":["FORMAT_CONFIGS","ClipboardManager","options","__publicField","points","opts","text","seriesIds","p","error","seriesData","series","i","format","_a","_b","_c","config","separator","lineSeparator","lines","headerParts","point","rowParts","seriesName","data","obj","sepRow","value","precision","threshold","factor","textarea","detectedFormat","startIndex","parts","x","y","trimmed","items","item","globalClipboardManager","getClipboardManager","copyToClipboard","formatData","manager","manifestClipboard","PluginClipboard","_config","_ctx"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"clipboard.js","sources":["../../src/core/clipboard/index.ts","../../src/plugins/clipboard/index.ts"],"sourcesContent":["/**\n * Velo Plot - Clipboard Module\n * \n * Provides clipboard operations for copying chart data to various formats.\n * Supports copying selected points, visible data, or all data.\n * \n * @module clipboard\n */\n\n// ============================================\n// Types\n// ============================================\n\nexport type ClipboardFormat = 'tsv' | 'csv' | 'json' | 'markdown';\n\nexport interface ClipboardOptions {\n /** Output format (default: 'tsv' - Excel compatible) */\n format?: ClipboardFormat;\n /** Include column headers (default: true) */\n includeHeaders?: boolean;\n /** Decimal precision (default: 6) */\n precision?: number;\n /** Use scientific notation for very large/small numbers (default: true) */\n scientific?: boolean;\n /** Scientific notation threshold (default: 1e6) */\n scientificThreshold?: number;\n /** Custom column separator (overrides format default) */\n separator?: string;\n /** Custom line separator (default: '\\n') */\n lineSeparator?: string;\n /** Include series name in output (default: true for multi-series) */\n includeSeriesName?: boolean;\n /** Custom header names */\n headers?: {\n x?: string;\n y?: string;\n series?: string;\n };\n}\n\nexport interface ClipboardDataPoint {\n x: number;\n y: number;\n seriesId?: string;\n seriesName?: string;\n index?: number;\n}\n\nexport interface ClipboardResult {\n /** Whether the copy was successful */\n success: boolean;\n /** Number of points copied */\n pointCount: number;\n /** Number of series included */\n seriesCount: number;\n /** The formatted text that was copied */\n text?: string;\n /** Error message if failed */\n error?: string;\n}\n\n// ============================================\n// Format Helpers\n// ============================================\n\nconst FORMAT_CONFIGS: Record<ClipboardFormat, { separator: string; quote: boolean; extension: string }> = {\n tsv: { separator: '\\t', quote: false, extension: 'tsv' },\n csv: { separator: ',', quote: true, extension: 'csv' },\n json: { separator: '', quote: false, extension: 'json' },\n markdown: { separator: ' | ', quote: false, extension: 'md' },\n};\n\n// ============================================\n// Clipboard Manager\n// ============================================\n\nexport class ClipboardManager {\n private defaultOptions: ClipboardOptions = {\n format: 'tsv',\n includeHeaders: true,\n precision: 6,\n scientific: true,\n scientificThreshold: 1e6,\n lineSeparator: '\\n',\n includeSeriesName: false,\n };\n\n constructor(options?: Partial<ClipboardOptions>) {\n if (options) {\n this.defaultOptions = { ...this.defaultOptions, ...options };\n }\n }\n\n /**\n * Copy data points to clipboard\n */\n async copyPoints(\n points: ClipboardDataPoint[],\n options?: Partial<ClipboardOptions>\n ): Promise<ClipboardResult> {\n const opts = { ...this.defaultOptions, ...options };\n \n if (!points || points.length === 0) {\n return {\n success: false,\n pointCount: 0,\n seriesCount: 0,\n error: 'No data points to copy',\n };\n }\n\n try {\n const text = this.formatPoints(points, opts);\n await this.writeToClipboard(text);\n\n const seriesIds = new Set(points.map(p => p.seriesId).filter(Boolean));\n \n return {\n success: true,\n pointCount: points.length,\n seriesCount: seriesIds.size || 1,\n text,\n };\n } catch (error) {\n return {\n success: false,\n pointCount: 0,\n seriesCount: 0,\n error: error instanceof Error ? error.message : 'Failed to copy to clipboard',\n };\n }\n }\n\n /**\n * Copy series data to clipboard\n */\n async copySeries(\n seriesData: { id: string; name?: string; x: Float32Array | Float64Array; y: Float32Array | Float64Array }[],\n options?: Partial<ClipboardOptions>\n ): Promise<ClipboardResult> {\n const points: ClipboardDataPoint[] = [];\n \n for (const series of seriesData) {\n for (let i = 0; i < series.x.length; i++) {\n points.push({\n x: series.x[i],\n y: series.y[i],\n seriesId: series.id,\n seriesName: series.name || series.id,\n index: i,\n });\n }\n }\n\n // Enable series name if multiple series\n const opts = { ...options };\n if (seriesData.length > 1 && opts.includeSeriesName === undefined) {\n opts.includeSeriesName = true;\n }\n\n return this.copyPoints(points, opts);\n }\n\n /**\n * Format data points to string\n */\n formatPoints(points: ClipboardDataPoint[], options: ClipboardOptions): string {\n const format = options.format || 'tsv';\n \n if (format === 'json') {\n return this.formatAsJson(points, options);\n }\n \n if (format === 'markdown') {\n return this.formatAsMarkdown(points, options);\n }\n\n return this.formatAsDelimited(points, options);\n }\n\n /**\n * Format as delimited text (TSV/CSV)\n */\n private formatAsDelimited(points: ClipboardDataPoint[], options: ClipboardOptions): string {\n const format = options.format || 'tsv';\n const config = FORMAT_CONFIGS[format];\n const separator = options.separator || config.separator;\n const lineSeparator = options.lineSeparator || '\\n';\n const lines: string[] = [];\n\n // Headers\n if (options.includeHeaders) {\n const headerParts: string[] = [];\n if (options.includeSeriesName) {\n headerParts.push(options.headers?.series || 'Series');\n }\n headerParts.push(options.headers?.x || 'X');\n headerParts.push(options.headers?.y || 'Y');\n lines.push(headerParts.join(separator));\n }\n\n // Data rows\n for (const point of points) {\n const rowParts: string[] = [];\n \n if (options.includeSeriesName) {\n const seriesName = point.seriesName || point.seriesId || '';\n rowParts.push(config.quote ? `\"${seriesName}\"` : seriesName);\n }\n \n rowParts.push(this.formatNumber(point.x, options));\n rowParts.push(this.formatNumber(point.y, options));\n \n lines.push(rowParts.join(separator));\n }\n\n return lines.join(lineSeparator);\n }\n\n /**\n * Format as JSON\n */\n private formatAsJson(points: ClipboardDataPoint[], options: ClipboardOptions): string {\n const data = points.map(p => {\n const obj: Record<string, unknown> = {\n x: this.roundNumber(p.x, options.precision || 6),\n y: this.roundNumber(p.y, options.precision || 6),\n };\n if (options.includeSeriesName && p.seriesId) {\n obj.series = p.seriesName || p.seriesId;\n }\n return obj;\n });\n\n return JSON.stringify(data, null, 2);\n }\n\n /**\n * Format as Markdown table\n */\n private formatAsMarkdown(points: ClipboardDataPoint[], options: ClipboardOptions): string {\n const lines: string[] = [];\n const separator = ' | ';\n\n // Header\n const headerParts: string[] = [];\n if (options.includeSeriesName) {\n headerParts.push(options.headers?.series || 'Series');\n }\n headerParts.push(options.headers?.x || 'X');\n headerParts.push(options.headers?.y || 'Y');\n \n lines.push('| ' + headerParts.join(separator) + ' |');\n \n // Separator row\n const sepRow = headerParts.map(() => '---');\n lines.push('| ' + sepRow.join(separator) + ' |');\n\n // Data rows\n for (const point of points) {\n const rowParts: string[] = [];\n \n if (options.includeSeriesName) {\n rowParts.push(point.seriesName || point.seriesId || '');\n }\n \n rowParts.push(this.formatNumber(point.x, options));\n rowParts.push(this.formatNumber(point.y, options));\n \n lines.push('| ' + rowParts.join(separator) + ' |');\n }\n\n return lines.join('\\n');\n }\n\n /**\n * Format a number for output\n */\n private formatNumber(value: number, options: ClipboardOptions): string {\n const precision = options.precision ?? 6;\n const threshold = options.scientificThreshold ?? 1e6;\n\n if (!isFinite(value)) {\n return value.toString();\n }\n\n // Use scientific notation for very large or very small numbers\n if (options.scientific && (Math.abs(value) >= threshold || (Math.abs(value) < 1e-4 && value !== 0))) {\n return value.toExponential(precision);\n }\n\n return this.roundNumber(value, precision).toString();\n }\n\n /**\n * Round a number to specified precision\n */\n private roundNumber(value: number, precision: number): number {\n const factor = Math.pow(10, precision);\n return Math.round(value * factor) / factor;\n }\n\n /**\n * Write text to system clipboard\n */\n private async writeToClipboard(text: string): Promise<void> {\n if (navigator.clipboard && navigator.clipboard.writeText) {\n await navigator.clipboard.writeText(text);\n } else {\n // Fallback for older browsers\n this.fallbackCopyToClipboard(text);\n }\n }\n\n /**\n * Fallback clipboard copy using hidden textarea\n */\n private fallbackCopyToClipboard(text: string): void {\n const textarea = document.createElement('textarea');\n textarea.value = text;\n textarea.style.position = 'fixed';\n textarea.style.left = '-9999px';\n textarea.style.top = '-9999px';\n document.body.appendChild(textarea);\n textarea.focus();\n textarea.select();\n \n try {\n document.execCommand('copy');\n } finally {\n document.body.removeChild(textarea);\n }\n }\n\n /**\n * Read from clipboard (for paste functionality)\n */\n async readFromClipboard(): Promise<string | null> {\n if (navigator.clipboard && navigator.clipboard.readText) {\n try {\n return await navigator.clipboard.readText();\n } catch {\n return null;\n }\n }\n return null;\n }\n\n /**\n * Parse clipboard text to data points\n */\n parseClipboardData(text: string, format?: ClipboardFormat): ClipboardDataPoint[] {\n const points: ClipboardDataPoint[] = [];\n \n // Try to detect format\n const detectedFormat = format || this.detectFormat(text);\n \n if (detectedFormat === 'json') {\n return this.parseJson(text);\n }\n\n // Parse as delimited\n const lines = text.trim().split(/\\r?\\n/);\n const separator = detectedFormat === 'csv' ? ',' : detectedFormat === 'tsv' ? '\\t' : ',';\n \n // Skip header if present\n const hasHeader = lines.length > 0 && /^[a-zA-Z]/.test(lines[0].trim());\n const startIndex = hasHeader ? 1 : 0;\n\n for (let i = startIndex; i < lines.length; i++) {\n const parts = lines[i].split(separator).map(p => p.trim().replace(/^\"|\"$/g, ''));\n \n if (parts.length >= 2) {\n const x = parseFloat(parts[0]);\n const y = parseFloat(parts[1]);\n \n if (!isNaN(x) && !isNaN(y)) {\n points.push({ x, y, index: i - startIndex });\n }\n }\n }\n\n return points;\n }\n\n /**\n * Detect format from text content\n */\n private detectFormat(text: string): ClipboardFormat {\n const trimmed = text.trim();\n \n if (trimmed.startsWith('[') || trimmed.startsWith('{')) {\n return 'json';\n }\n \n if (trimmed.includes('\\t')) {\n return 'tsv';\n }\n \n if (trimmed.includes(' | ')) {\n return 'markdown';\n }\n \n return 'csv';\n }\n\n /**\n * Parse JSON data\n */\n private parseJson(text: string): ClipboardDataPoint[] {\n try {\n const data = JSON.parse(text);\n const points: ClipboardDataPoint[] = [];\n const items = Array.isArray(data) ? data : [data];\n \n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n if (typeof item.x === 'number' && typeof item.y === 'number') {\n points.push({\n x: item.x,\n y: item.y,\n seriesId: item.series || item.seriesId,\n seriesName: item.seriesName || item.series,\n index: i,\n });\n }\n }\n \n return points;\n } catch {\n return [];\n }\n }\n\n /**\n * Set default options\n */\n setDefaults(options: Partial<ClipboardOptions>): void {\n this.defaultOptions = { ...this.defaultOptions, ...options };\n }\n\n /**\n * Get current default options\n */\n getDefaults(): ClipboardOptions {\n return { ...this.defaultOptions };\n }\n}\n\n// ============================================\n// Convenience Functions\n// ============================================\n\n/** Singleton instance for global use */\nlet globalClipboardManager: ClipboardManager | null = null;\n\n/**\n * Get the global clipboard manager instance\n */\nexport function getClipboardManager(): ClipboardManager {\n if (!globalClipboardManager) {\n globalClipboardManager = new ClipboardManager();\n }\n return globalClipboardManager;\n}\n\n/**\n * Copy data points to clipboard (convenience function)\n */\nexport async function copyToClipboard(\n points: ClipboardDataPoint[],\n options?: Partial<ClipboardOptions>\n): Promise<ClipboardResult> {\n return getClipboardManager().copyPoints(points, options);\n}\n\n/**\n * Format data as delimited string (without copying)\n */\nexport function formatData(\n points: ClipboardDataPoint[],\n options?: Partial<ClipboardOptions>\n): string {\n const manager = getClipboardManager();\n return manager.formatPoints(points, { ...manager.getDefaults(), ...options });\n}\n","/**\n * VeloPlot Engine - Clipboard Plugin\n * \n * Provides clipboard integration for copying chart data and images.\n * \n * @module plugins/clipboard\n */\n\nexport * from \"../../core/clipboard\";\n\nimport type { PluginManifest, ChartPlugin, PluginContext } from \"../types\";\n\nexport interface PluginClipboardConfig {\n /** Default format for copied data: 'csv' | 'json' | 'image' */\n defaultFormat?: string;\n}\n\nconst manifestClipboard: PluginManifest = {\n name: \"velo-plot-clipboard\",\n version: \"1.0.0\",\n description: \"Clipboard integration for velo-plot\",\n provides: [\"interaction\"],\n tags: [\"clipboard\", \"copy\", \"paste\", \"export\"],\n};\n\n/**\n * VeloPlot Clipboard Plugin\n * \n * Adds support for copying data and screenshots to the clipboard.\n */\nexport function PluginClipboard(_config: PluginClipboardConfig = {}): ChartPlugin<PluginClipboardConfig> {\n return {\n manifest: manifestClipboard,\n\n onInit(_ctx: PluginContext) {\n },\n\n onDestroy(_ctx: PluginContext) {\n },\n\n api: {\n copyCurrentView() {\n // Implementation would call copyToClipboard with data from current view\n }\n }\n };\n}\n\nexport default PluginClipboard;\n"],"names":["FORMAT_CONFIGS","ClipboardManager","options","__publicField","points","opts","text","seriesIds","p","error","seriesData","series","i","format","_a","_b","_c","config","separator","lineSeparator","lines","headerParts","point","rowParts","seriesName","data","obj","sepRow","value","precision","threshold","factor","textarea","detectedFormat","startIndex","parts","x","y","trimmed","items","item","globalClipboardManager","getClipboardManager","copyToClipboard","formatData","manager","manifestClipboard","PluginClipboard","_config","_ctx"],"mappings":";;;AAiEA,MAAMA,IAAoG;AAAA,EACxG,KAAK,EAAE,WAAW,KAAM,OAAO,IAAO,WAAW,MAAA;AAAA,EACjD,KAAK,EAAE,WAAW,KAAK,OAAO,IAAM,WAAW,MAAA;AAAA,EAC/C,MAAM,EAAE,WAAW,IAAI,OAAO,IAAO,WAAW,OAAA;AAAA,EAChD,UAAU,EAAE,WAAW,OAAO,OAAO,IAAO,WAAW,KAAA;AACzD;AAMO,MAAMC,EAAiB;AAAA,EAW5B,YAAYC,GAAqC;AAVzC,IAAAC,EAAA,wBAAmC;AAAA,MACzC,QAAQ;AAAA,MACR,gBAAgB;AAAA,MAChB,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,qBAAqB;AAAA,MACrB,eAAe;AAAA;AAAA,MACf,mBAAmB;AAAA,IAAA;AAInB,IAAID,MACF,KAAK,iBAAiB,EAAE,GAAG,KAAK,gBAAgB,GAAGA,EAAA;AAAA,EAEvD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WACJE,GACAF,GAC0B;AAC1B,UAAMG,IAAO,EAAE,GAAG,KAAK,gBAAgB,GAAGH,EAAA;AAE1C,QAAI,CAACE,KAAUA,EAAO,WAAW;AAC/B,aAAO;AAAA,QACL,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,aAAa;AAAA,QACb,OAAO;AAAA,MAAA;AAIX,QAAI;AACF,YAAME,IAAO,KAAK,aAAaF,GAAQC,CAAI;AAC3C,YAAM,KAAK,iBAAiBC,CAAI;AAEhC,YAAMC,IAAY,IAAI,IAAIH,EAAO,IAAI,CAAAI,MAAKA,EAAE,QAAQ,EAAE,OAAO,OAAO,CAAC;AAErE,aAAO;AAAA,QACL,SAAS;AAAA,QACT,YAAYJ,EAAO;AAAA,QACnB,aAAaG,EAAU,QAAQ;AAAA,QAC/B,MAAAD;AAAA,MAAA;AAAA,IAEJ,SAASG,GAAO;AACd,aAAO;AAAA,QACL,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,aAAa;AAAA,QACb,OAAOA,aAAiB,QAAQA,EAAM,UAAU;AAAA,MAAA;AAAA,IAEpD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WACJC,GACAR,GAC0B;AAC1B,UAAME,IAA+B,CAAA;AAErC,eAAWO,KAAUD;AACnB,eAASE,IAAI,GAAGA,IAAID,EAAO,EAAE,QAAQC;AACnC,QAAAR,EAAO,KAAK;AAAA,UACV,GAAGO,EAAO,EAAEC,CAAC;AAAA,UACb,GAAGD,EAAO,EAAEC,CAAC;AAAA,UACb,UAAUD,EAAO;AAAA,UACjB,YAAYA,EAAO,QAAQA,EAAO;AAAA,UAClC,OAAOC;AAAA,QAAA,CACR;AAKL,UAAMP,IAAO,EAAE,GAAGH,EAAA;AAClB,WAAIQ,EAAW,SAAS,KAAKL,EAAK,sBAAsB,WACtDA,EAAK,oBAAoB,KAGpB,KAAK,WAAWD,GAAQC,CAAI;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKA,aAAaD,GAA8BF,GAAmC;AAC5E,UAAMW,IAASX,EAAQ,UAAU;AAEjC,WAAIW,MAAW,SACN,KAAK,aAAaT,GAAQF,CAAO,IAGtCW,MAAW,aACN,KAAK,iBAAiBT,GAAQF,CAAO,IAGvC,KAAK,kBAAkBE,GAAQF,CAAO;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAkBE,GAA8BF,GAAmC;AAtH7F,QAAAY,GAAAC,GAAAC;AAuHI,UAAMH,IAASX,EAAQ,UAAU,OAC3Be,IAASjB,EAAea,CAAM,GAC9BK,IAAYhB,EAAQ,aAAae,EAAO,WACxCE,IAAgBjB,EAAQ,iBAAiB;AAAA,GACzCkB,IAAkB,CAAA;AAGxB,QAAIlB,EAAQ,gBAAgB;AAC1B,YAAMmB,IAAwB,CAAA;AAC9B,MAAInB,EAAQ,qBACVmB,EAAY,OAAKP,IAAAZ,EAAQ,YAAR,gBAAAY,EAAiB,WAAU,QAAQ,GAEtDO,EAAY,OAAKN,IAAAb,EAAQ,YAAR,gBAAAa,EAAiB,MAAK,GAAG,GAC1CM,EAAY,OAAKL,IAAAd,EAAQ,YAAR,gBAAAc,EAAiB,MAAK,GAAG,GAC1CI,EAAM,KAAKC,EAAY,KAAKH,CAAS,CAAC;AAAA,IACxC;AAGA,eAAWI,KAASlB,GAAQ;AAC1B,YAAMmB,IAAqB,CAAA;AAE3B,UAAIrB,EAAQ,mBAAmB;AAC7B,cAAMsB,IAAaF,EAAM,cAAcA,EAAM,YAAY;AACzD,QAAAC,EAAS,KAAKN,EAAO,QAAQ,IAAIO,CAAU,MAAMA,CAAU;AAAA,MAC7D;AAEA,MAAAD,EAAS,KAAK,KAAK,aAAaD,EAAM,GAAGpB,CAAO,CAAC,GACjDqB,EAAS,KAAK,KAAK,aAAaD,EAAM,GAAGpB,CAAO,CAAC,GAEjDkB,EAAM,KAAKG,EAAS,KAAKL,CAAS,CAAC;AAAA,IACrC;AAEA,WAAOE,EAAM,KAAKD,CAAa;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAaf,GAA8BF,GAAmC;AACpF,UAAMuB,IAAOrB,EAAO,IAAI,CAAAI,MAAK;AAC3B,YAAMkB,IAA+B;AAAA,QACnC,GAAG,KAAK,YAAYlB,EAAE,GAAGN,EAAQ,aAAa,CAAC;AAAA,QAC/C,GAAG,KAAK,YAAYM,EAAE,GAAGN,EAAQ,aAAa,CAAC;AAAA,MAAA;AAEjD,aAAIA,EAAQ,qBAAqBM,EAAE,aACjCkB,EAAI,SAASlB,EAAE,cAAcA,EAAE,WAE1BkB;AAAA,IACT,CAAC;AAED,WAAO,KAAK,UAAUD,GAAM,MAAM,CAAC;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKQ,iBAAiBrB,GAA8BF,GAAmC;AA/K5F,QAAAY,GAAAC,GAAAC;AAgLI,UAAMI,IAAkB,CAAA,GAClBF,IAAY,OAGZG,IAAwB,CAAA;AAC9B,IAAInB,EAAQ,qBACVmB,EAAY,OAAKP,IAAAZ,EAAQ,YAAR,gBAAAY,EAAiB,WAAU,QAAQ,GAEtDO,EAAY,OAAKN,IAAAb,EAAQ,YAAR,gBAAAa,EAAiB,MAAK,GAAG,GAC1CM,EAAY,OAAKL,IAAAd,EAAQ,YAAR,gBAAAc,EAAiB,MAAK,GAAG,GAE1CI,EAAM,KAAK,OAAOC,EAAY,KAAKH,CAAS,IAAI,IAAI;AAGpD,UAAMS,IAASN,EAAY,IAAI,MAAM,KAAK;AAC1C,IAAAD,EAAM,KAAK,OAAOO,EAAO,KAAKT,CAAS,IAAI,IAAI;AAG/C,eAAWI,KAASlB,GAAQ;AAC1B,YAAMmB,IAAqB,CAAA;AAE3B,MAAIrB,EAAQ,qBACVqB,EAAS,KAAKD,EAAM,cAAcA,EAAM,YAAY,EAAE,GAGxDC,EAAS,KAAK,KAAK,aAAaD,EAAM,GAAGpB,CAAO,CAAC,GACjDqB,EAAS,KAAK,KAAK,aAAaD,EAAM,GAAGpB,CAAO,CAAC,GAEjDkB,EAAM,KAAK,OAAOG,EAAS,KAAKL,CAAS,IAAI,IAAI;AAAA,IACnD;AAEA,WAAOE,EAAM,KAAK;AAAA,CAAI;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAaQ,GAAe1B,GAAmC;AACrE,UAAM2B,IAAY3B,EAAQ,aAAa,GACjC4B,IAAY5B,EAAQ,uBAAuB;AAEjD,WAAK,SAAS0B,CAAK,IAKf1B,EAAQ,eAAe,KAAK,IAAI0B,CAAK,KAAKE,KAAc,KAAK,IAAIF,CAAK,IAAI,QAAQA,MAAU,KACvFA,EAAM,cAAcC,CAAS,IAG/B,KAAK,YAAYD,GAAOC,CAAS,EAAE,SAAA,IARjCD,EAAM,SAAA;AAAA,EASjB;AAAA;AAAA;AAAA;AAAA,EAKQ,YAAYA,GAAeC,GAA2B;AAC5D,UAAME,IAAS,KAAK,IAAI,IAAIF,CAAS;AACrC,WAAO,KAAK,MAAMD,IAAQG,CAAM,IAAIA;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,iBAAiBzB,GAA6B;AAC1D,IAAI,UAAU,aAAa,UAAU,UAAU,YAC7C,MAAM,UAAU,UAAU,UAAUA,CAAI,IAGxC,KAAK,wBAAwBA,CAAI;AAAA,EAErC;AAAA;AAAA;AAAA;AAAA,EAKQ,wBAAwBA,GAAoB;AAClD,UAAM0B,IAAW,SAAS,cAAc,UAAU;AAClD,IAAAA,EAAS,QAAQ1B,GACjB0B,EAAS,MAAM,WAAW,SAC1BA,EAAS,MAAM,OAAO,WACtBA,EAAS,MAAM,MAAM,WACrB,SAAS,KAAK,YAAYA,CAAQ,GAClCA,EAAS,MAAA,GACTA,EAAS,OAAA;AAET,QAAI;AACF,eAAS,YAAY,MAAM;AAAA,IAC7B,UAAA;AACE,eAAS,KAAK,YAAYA,CAAQ;AAAA,IACpC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,oBAA4C;AAChD,QAAI,UAAU,aAAa,UAAU,UAAU;AAC7C,UAAI;AACF,eAAO,MAAM,UAAU,UAAU,SAAA;AAAA,MACnC,QAAQ;AACN,eAAO;AAAA,MACT;AAEF,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,mBAAmB1B,GAAcO,GAAgD;AAC/E,UAAMT,IAA+B,CAAA,GAG/B6B,IAAiBpB,KAAU,KAAK,aAAaP,CAAI;AAEvD,QAAI2B,MAAmB;AACrB,aAAO,KAAK,UAAU3B,CAAI;AAI5B,UAAMc,IAAQd,EAAK,KAAA,EAAO,MAAM,OAAO,GACjCY,IAAYe,MAAmB,QAAQ,MAAMA,MAAmB,QAAQ,MAAO,KAI/EC,IADYd,EAAM,SAAS,KAAK,YAAY,KAAKA,EAAM,CAAC,EAAE,MAAM,IACvC,IAAI;AAEnC,aAASR,IAAIsB,GAAYtB,IAAIQ,EAAM,QAAQR,KAAK;AAC9C,YAAMuB,IAAQf,EAAMR,CAAC,EAAE,MAAMM,CAAS,EAAE,IAAI,CAAAV,MAAKA,EAAE,KAAA,EAAO,QAAQ,UAAU,EAAE,CAAC;AAE/E,UAAI2B,EAAM,UAAU,GAAG;AACrB,cAAMC,IAAI,WAAWD,EAAM,CAAC,CAAC,GACvBE,IAAI,WAAWF,EAAM,CAAC,CAAC;AAE7B,QAAI,CAAC,MAAMC,CAAC,KAAK,CAAC,MAAMC,CAAC,KACvBjC,EAAO,KAAK,EAAE,GAAAgC,GAAG,GAAAC,GAAG,OAAOzB,IAAIsB,GAAY;AAAA,MAE/C;AAAA,IACF;AAEA,WAAO9B;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAaE,GAA+B;AAClD,UAAMgC,IAAUhC,EAAK,KAAA;AAErB,WAAIgC,EAAQ,WAAW,GAAG,KAAKA,EAAQ,WAAW,GAAG,IAC5C,SAGLA,EAAQ,SAAS,GAAI,IAChB,QAGLA,EAAQ,SAAS,KAAK,IACjB,aAGF;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,UAAUhC,GAAoC;AACpD,QAAI;AACF,YAAMmB,IAAO,KAAK,MAAMnB,CAAI,GACtBF,IAA+B,CAAA,GAC/BmC,IAAQ,MAAM,QAAQd,CAAI,IAAIA,IAAO,CAACA,CAAI;AAEhD,eAASb,IAAI,GAAGA,IAAI2B,EAAM,QAAQ3B,KAAK;AACrC,cAAM4B,IAAOD,EAAM3B,CAAC;AACpB,QAAI,OAAO4B,EAAK,KAAM,YAAY,OAAOA,EAAK,KAAM,YAClDpC,EAAO,KAAK;AAAA,UACV,GAAGoC,EAAK;AAAA,UACR,GAAGA,EAAK;AAAA,UACR,UAAUA,EAAK,UAAUA,EAAK;AAAA,UAC9B,YAAYA,EAAK,cAAcA,EAAK;AAAA,UACpC,OAAO5B;AAAA,QAAA,CACR;AAAA,MAEL;AAEA,aAAOR;AAAA,IACT,QAAQ;AACN,aAAO,CAAA;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,YAAYF,GAA0C;AACpD,SAAK,iBAAiB,EAAE,GAAG,KAAK,gBAAgB,GAAGA,EAAA;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA,EAKA,cAAgC;AAC9B,WAAO,EAAE,GAAG,KAAK,eAAA;AAAA,EACnB;AACF;AAOA,IAAIuC,IAAkD;AAK/C,SAASC,IAAwC;AACtD,SAAKD,MACHA,IAAyB,IAAIxC,EAAA,IAExBwC;AACT;AAKA,eAAsBE,EACpBvC,GACAF,GAC0B;AAC1B,SAAOwC,EAAA,EAAsB,WAAWtC,GAAQF,CAAO;AACzD;AAKO,SAAS0C,EACdxC,GACAF,GACQ;AACR,QAAM2C,IAAUH,EAAA;AAChB,SAAOG,EAAQ,aAAazC,GAAQ,EAAE,GAAGyC,EAAQ,YAAA,GAAe,GAAG3C,GAAS;AAC9E;ACpdA,MAAM4C,IAAoC;AAAA,EACtC,MAAM;AAAA,EACN,SAAS;AAAA,EACT,aAAa;AAAA,EACb,UAAU,CAAC,aAAa;AAAA,EACxB,MAAM,CAAC,aAAa,QAAQ,SAAS,QAAQ;AACjD;AAOO,SAASC,EAAgBC,IAAiC,IAAwC;AACrG,SAAO;AAAA,IACH,UAAUF;AAAA,IAEV,OAAOG,GAAqB;AAAA,IAC5B;AAAA,IAEA,UAAUA,GAAqB;AAAA,IAC/B;AAAA,IAEA,KAAK;AAAA,MACD,kBAAkB;AAAA,MAElB;AAAA,IAAA;AAAA,EACJ;AAER;"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export * from './context-menu/index'
|
|
2
|
-
import
|
|
3
|
-
export default
|
|
2
|
+
import VeloPlot from './context-menu/index'
|
|
3
|
+
export default VeloPlot
|
|
@@ -273,7 +273,7 @@ const _ = [
|
|
|
273
273
|
name: "velo-plot-context-menu",
|
|
274
274
|
version: "1.0.0",
|
|
275
275
|
description: "Customizable right-click context menu for velo-plot",
|
|
276
|
-
author: "
|
|
276
|
+
author: "Velo Plot Team",
|
|
277
277
|
provides: ["interaction"],
|
|
278
278
|
tags: ["context-menu", "right-click", "menu", "ui"]
|
|
279
279
|
};
|