velo-plot 3.0.0 → 4.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -15
- package/dist/ChartCore-KYG2HTcK.js +7474 -0
- package/dist/ChartCore-KYG2HTcK.js.map +1 -0
- package/dist/GpuChartRenderer-Dxc0hrQA.js +75 -0
- package/dist/GpuChartRenderer-Dxc0hrQA.js.map +1 -0
- package/dist/{index.core-BmZe2jRQ.js → PluginRegistry-CDf_jcnp.js} +19 -33
- package/dist/PluginRegistry-CDf_jcnp.js.map +1 -0
- package/dist/SVGDocumentBuilder-C-uLkcFW.js +83 -0
- package/dist/SVGDocumentBuilder-C-uLkcFW.js.map +1 -0
- package/dist/angular-hooks.js +1 -1
- package/dist/angular.js +8 -8
- package/dist/{axisFormat-CzumxpCL.js → axisFormat-Sz4WIJfQ.js} +2 -2
- package/dist/{axisFormat-CzumxpCL.js.map → axisFormat-Sz4WIJfQ.js.map} +1 -1
- package/dist/{chartSyncBridge-DbWrwtyP.js → chartSyncBridge-C1uRy0ZS.js} +12 -11
- package/dist/{chartSyncBridge-DbWrwtyP.js.map → chartSyncBridge-C1uRy0ZS.js.map} +1 -1
- package/dist/core/ChartStatistics.d.ts +1 -1
- package/dist/core/chart/ChartCore.d.ts +19 -20
- package/dist/core/chart/ChartFeatureHooks.d.ts +7 -0
- package/dist/core/chart/ChartRenderLoop.d.ts +5 -0
- package/dist/core/chart/ChartRenderer.d.ts +9 -0
- package/dist/core/chart/ChartSetup.d.ts +1 -0
- package/dist/core/chart/chartExportPatch.d.ts +2 -0
- package/dist/core/chart/exporter/SVGExporter.d.ts +9 -7
- package/dist/core/chart/exporter/svg/SVGDocumentBuilder.d.ts +27 -0
- package/dist/core/chart/exporter/svg/SVGExportContext.d.ts +147 -0
- package/dist/core/chart/exporter/svg/SVGOrchestrator.d.ts +3 -0
- package/dist/core/chart/exporter/svg/SVGThemeAdapter.d.ts +22 -0
- package/dist/core/chart/exporter/svg/__tests__/testFixtures.d.ts +46 -0
- package/dist/core/chart/exporter/svg/__tests__/visualTestUtils.d.ts +12 -0
- package/dist/core/chart/exporter/svg/overlay/axes.d.ts +4 -0
- package/dist/core/chart/exporter/svg/overlay/border.d.ts +4 -0
- package/dist/core/chart/exporter/svg/overlay/errorBars.d.ts +7 -0
- package/dist/core/chart/exporter/svg/overlay/grid.d.ts +4 -0
- package/dist/core/chart/exporter/svg/overlay/index.d.ts +12 -0
- package/dist/core/chart/exporter/svg/overlay/legend.d.ts +4 -0
- package/dist/core/chart/exporter/svg/overlay/pluginCharts.d.ts +6 -0
- package/dist/core/chart/exporter/svg/overlay/polarGrid.d.ts +4 -0
- package/dist/core/chart/exporter/svg/overlay/specialChart.d.ts +15 -0
- package/dist/core/chart/exporter/svg/overlay/title.d.ts +4 -0
- package/dist/core/chart/exporter/svg/plugins/annotations.d.ts +5 -0
- package/dist/core/chart/exporter/svg/plugins/brokenAxis.d.ts +20 -0
- package/dist/core/chart/exporter/svg/plugins/latex.d.ts +9 -0
- package/dist/core/chart/exporter/svg/plugins/register.d.ts +8 -0
- package/dist/core/chart/exporter/svg/plugins/regression.d.ts +33 -0
- package/dist/core/chart/exporter/svg/plugins/roi.d.ts +12 -0
- package/dist/core/chart/exporter/svg/plugins/tradeMarkers.d.ts +3 -0
- package/dist/core/chart/exporter/svg/plugins/types.d.ts +28 -0
- package/dist/core/chart/exporter/svg/plugins/watermark.d.ts +13 -0
- package/dist/core/chart/exporter/svg/series/band.d.ts +6 -0
- package/dist/core/chart/exporter/svg/series/bar.d.ts +6 -0
- package/dist/core/chart/exporter/svg/series/boxplot.d.ts +6 -0
- package/dist/core/chart/exporter/svg/series/candlestick.d.ts +6 -0
- package/dist/core/chart/exporter/svg/series/finitePoints.d.ts +6 -0
- package/dist/core/chart/exporter/svg/series/gauge.d.ts +5 -0
- package/dist/core/chart/exporter/svg/series/heatmap.d.ts +6 -0
- package/dist/core/chart/exporter/svg/series/indicator.d.ts +6 -0
- package/dist/core/chart/exporter/svg/series/line.d.ts +12 -0
- package/dist/core/chart/exporter/svg/series/polar.d.ts +6 -0
- package/dist/core/chart/exporter/svg/series/radar.d.ts +5 -0
- package/dist/core/chart/exporter/svg/series/registry.d.ts +10 -0
- package/dist/core/chart/exporter/svg/series/sankey.d.ts +5 -0
- package/dist/core/chart/exporter/svg/series/scatter.d.ts +1 -0
- package/dist/core/chart/exporter/svg/series/ternary.d.ts +7 -0
- package/dist/core/chart/exporter/svg/series/waterfall.d.ts +6 -0
- package/dist/core/chart/exporter/svg/seriesAtTimestamp.d.ts +4 -0
- package/dist/core/chart/exporter/svg/seriesUtils.d.ts +3 -0
- package/dist/core/chart/exporter/svg/symbols.d.ts +5 -0
- package/dist/core/chart/exporter/svg/tickUtils.d.ts +9 -0
- package/dist/core/chart/mountSVGString.d.ts +5 -0
- package/dist/core/chart/overlaySeriesRegistry.d.ts +7 -0
- package/dist/core/chart/series/SeriesActions.d.ts +1 -0
- package/dist/core/chart/series/SeriesBufferLite.d.ts +13 -0
- package/dist/core/chart/series/seriesOptionsRegistry.d.ts +8 -0
- package/dist/core/chart/series/seriesTypeRegistry.d.ts +5 -0
- package/dist/core/chart/types.d.ts +2 -2
- package/dist/core/stacked/StackSVGComposer.d.ts +14 -0
- package/dist/core/stacked/index.d.ts +3 -2
- package/dist/core/stacked/types.d.ts +12 -4
- package/dist/createStackedChart-DjA3aJAu.js +2761 -0
- package/dist/createStackedChart-DjA3aJAu.js.map +1 -0
- package/dist/{hooks-CYPCxoZx.js → hooks-4wQH27r9.js} +7 -7
- package/dist/{hooks-CYPCxoZx.js.map → hooks-4wQH27r9.js.map} +1 -1
- package/dist/{index-qunX30Xu.js → index-B7PTX94B.js} +2133 -2133
- package/dist/index-B7PTX94B.js.map +1 -0
- package/dist/{index-BMiZoKmm.js → index-BgrvqltV.js} +67 -67
- package/dist/index-BgrvqltV.js.map +1 -0
- package/dist/index-Bj-xyXY6.js +582 -0
- package/dist/index-Bj-xyXY6.js.map +1 -0
- package/dist/index-qhscKTDy.js.map +1 -1
- package/dist/index.core.d.ts +8 -6
- package/dist/index.d.ts +1 -14
- package/dist/plugins/3d.js +3 -1
- package/dist/plugins/3d.js.map +1 -1
- package/dist/plugins/PluginManager.d.ts +5 -0
- package/dist/plugins/analysis.js.map +1 -1
- package/dist/plugins/annotations.js +8 -7
- package/dist/plugins/annotations.js.map +1 -1
- package/dist/plugins/broken-axis.js +198 -152
- package/dist/plugins/broken-axis.js.map +1 -1
- package/dist/plugins/createPlugin.d.ts +8 -0
- package/dist/plugins/debug.js +32 -32
- package/dist/plugins/debug.js.map +1 -1
- package/dist/plugins/forecasting.js +273 -258
- package/dist/plugins/forecasting.js.map +1 -1
- package/dist/plugins/gpu.js +2033 -209
- package/dist/plugins/gpu.js.map +1 -1
- package/dist/plugins/i18n.js +286 -23
- package/dist/plugins/i18n.js.map +1 -1
- package/dist/plugins/latex.js +766 -207
- package/dist/plugins/latex.js.map +1 -1
- package/dist/plugins/loading/index.d.ts +1 -2
- package/dist/plugins/loading.js +3 -4
- package/dist/plugins/ml-integration.js +107 -93
- package/dist/plugins/ml-integration.js.map +1 -1
- package/dist/plugins/offscreen.js +11 -10
- package/dist/plugins/offscreen.js.map +1 -1
- package/dist/plugins/radar/types.d.ts +11 -0
- package/dist/plugins/radar.js +64 -53
- package/dist/plugins/radar.js.map +1 -1
- package/dist/plugins/regression.js +254 -256
- package/dist/plugins/regression.js.map +1 -1
- package/dist/plugins/roi/index.d.ts +2 -0
- package/dist/plugins/roi.js +184 -145
- package/dist/plugins/roi.js.map +1 -1
- package/dist/plugins/snapshot.js +20 -15
- package/dist/plugins/snapshot.js.map +1 -1
- package/dist/plugins/streaming.js +1 -1
- package/dist/plugins/tools.js +1 -1
- package/dist/plugins/types.d.ts +4 -0
- package/dist/react.js +55 -58
- package/dist/react.js.map +1 -1
- package/dist/regression-HNdyk1Dm.js +28 -0
- package/dist/regression-HNdyk1Dm.js.map +1 -0
- package/dist/renderer/ChartSeriesRenderer.d.ts +3 -2
- package/dist/renderer/NativeWebGLRenderer.d.ts +2 -1
- package/dist/renderer/SVGChartRenderer.d.ts +15 -0
- package/dist/renderer/SankeyRenderer.d.ts +1 -0
- package/dist/renderer/native/NativeWebGLRenderer.d.ts +5 -1
- package/dist/renderer/native/draw.d.ts +2 -47
- package/dist/renderer/native/drawCore.d.ts +27 -0
- package/dist/renderer/native/drawExtended.d.ts +29 -0
- package/dist/renderer/native/frameRenderExtended.d.ts +1 -0
- package/dist/renderer/native/frameRenderRegistry.d.ts +27 -0
- package/dist/renderer/native/programFactoryCore.d.ts +6 -0
- package/dist/renderer/native/programFactoryExtended.d.ts +4 -0
- package/dist/renderer/native/utils.d.ts +3 -29
- package/dist/renderer/native/utilsCore.d.ts +14 -0
- package/dist/renderer/native/utilsExtended.d.ts +17 -0
- package/dist/renderer/overlaySeriesExtended.d.ts +1 -0
- package/dist/renderer/registerExtendedSeries.d.ts +1 -0
- package/dist/renderer/registerSVG.d.ts +5 -0
- package/dist/renderer/registerWebGPU.d.ts +2 -0
- package/dist/renderer/sankeyLayout.d.ts +29 -0
- package/dist/renderer/seriesBufferExtended.d.ts +4 -0
- package/dist/scientific/index.d.ts +1 -5
- package/dist/scientific/registerScientific.d.ts +1 -0
- package/dist/scientific.js +41 -41
- package/dist/solid.js +56 -59
- package/dist/solid.js.map +1 -1
- package/dist/svelte.js +26 -29
- package/dist/svelte.js.map +1 -1
- package/dist/tickUtils-B_X-ha13.js +41 -0
- package/dist/tickUtils-B_X-ha13.js.map +1 -0
- package/dist/trading/index.d.ts +1 -4
- package/dist/trading/registerTrading.d.ts +3 -0
- package/dist/trading.js +42 -42
- package/dist/types.d.ts +5 -4
- package/dist/velo-plot.full.js +1951 -1275
- package/dist/velo-plot.full.js.map +1 -1
- package/dist/velo-plot.js +33 -28
- package/dist/velo-plot.js.map +1 -1
- package/dist/vue/VeloPlot.vue.d.ts +1 -1
- package/dist/vue/index.d.ts +33 -33
- package/dist/vue.js +17 -20
- package/dist/vue.js.map +1 -1
- package/package.json +14 -1
- package/dist/ChartCore-BpzRvN4Y.js +0 -8467
- package/dist/ChartCore-BpzRvN4Y.js.map +0 -1
- package/dist/createStackedChart-Dm-YqUT7.js +0 -756
- package/dist/createStackedChart-Dm-YqUT7.js.map +0 -1
- package/dist/gpuRenderer-BpaMYz-k.js +0 -1848
- package/dist/gpuRenderer-BpaMYz-k.js.map +0 -1
- package/dist/index-BMiZoKmm.js.map +0 -1
- package/dist/index-qunX30Xu.js.map +0 -1
- package/dist/index-x4stH3jD.js +0 -282
- package/dist/index-x4stH3jD.js.map +0 -1
- package/dist/index.core-BmZe2jRQ.js.map +0 -1
- package/dist/mockDatafeed-DHIDPcpX.js +0 -515
- package/dist/mockDatafeed-DHIDPcpX.js.map +0 -1
- package/dist/symbols-DT0eLlpW.js +0 -568
- package/dist/symbols-DT0eLlpW.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"offscreen.js","sources":["../../src/plugins/offscreen/pool.ts","../../src/plugins/offscreen/index.ts"],"sourcesContent":["/**\n * @fileoverview Worker Pool Manager for Offscreen Rendering\n * @module plugins/offscreen/pool\n */\n\nexport interface WorkerTask {\n id: string;\n priority: number;\n timestamp: number;\n resolve: (value: ImageBitmap) => void;\n reject: (error: Error) => void;\n}\n\nexport class WorkerPool {\n private workers: Worker[] = [];\n private availableWorkers: Set<number> = new Set();\n private taskQueue: WorkerTask[] = [];\n private activeJobs: Map<string, number> = new Map(); // taskId => workerIndex\n\n constructor(private size: number) {\n this.initialize();\n }\n\n private initialize(): void {\n const workerCode = `\n // Simple offscreen worker\n self.onmessage = (e) => {\n const { type, width, height, dpr } = e.data;\n \n if (type === 'render') {\n // Echo back - actual rendering logic would go here\n self.postMessage({ type: 'response', taskId: e.data.taskId });\n }\n };\n `;\n\n const blob = new Blob([workerCode], { type: 'application/javascript' });\n const workerUrl = URL.createObjectURL(blob);\n\n for (let i = 0; i < this.size; i++) {\n try {\n const worker = new Worker(workerUrl);\n worker.onmessage = (e) => this.handleWorkerMessage(i, e);\n worker.onerror = (e) => this.handleWorkerError(i, e);\n this.workers.push(worker);\n this.availableWorkers.add(i);\n } catch (error) {\n console.error(`Failed to create worker ${i}:`, error);\n }\n }\n\n URL.revokeObjectURL(workerUrl);\n }\n\n private handleWorkerMessage(workerIndex: number, event: MessageEvent): void {\n const { type, taskId, imageData, error } = event.data;\n\n if (type === 'response') {\n const task = this.findTask(taskId);\n if (task) {\n if (error) {\n task.reject(new Error(error));\n } else if (imageData) {\n task.resolve(imageData);\n }\n this.activeJobs.delete(taskId);\n this.availableWorkers.add(workerIndex);\n this.processQueue();\n }\n }\n }\n\n private handleWorkerError(workerIndex: number, error: ErrorEvent): void {\n console.error(`Worker ${workerIndex} error:`, error);\n // Find and reject any active task for this worker\n for (const [taskId, wIndex] of this.activeJobs.entries()) {\n if (wIndex === workerIndex) {\n const task = this.findTask(taskId);\n if (task) {\n task.reject(new Error(`Worker error: ${error.message}`));\n this.activeJobs.delete(taskId);\n }\n }\n }\n this.availableWorkers.add(workerIndex);\n this.processQueue();\n }\n\n private findTask(taskId: string): WorkerTask | undefined {\n return this.taskQueue.find(t => t.id === taskId);\n }\n\n private processQueue(): void {\n while (this.availableWorkers.size > 0 && this.taskQueue.length > 0) {\n // Sort by priority and timestamp\n this.taskQueue.sort((a, b) => {\n if (a.priority !== b.priority) return b.priority - a.priority;\n return a.timestamp - b.timestamp;\n });\n\n const task = this.taskQueue.shift();\n if (!task) break;\n\n const workerIndex = Array.from(this.availableWorkers)[0];\n this.availableWorkers.delete(workerIndex);\n this.activeJobs.set(task.id, workerIndex);\n\n // Send task to worker\n this.workers[workerIndex].postMessage({\n type: 'render',\n taskId: task.id,\n });\n }\n }\n\n public submit(priority: number = 0): Promise<ImageBitmap> {\n return new Promise((resolve, reject) => {\n const task: WorkerTask = {\n id: Math.random().toString(36).substring(7),\n priority,\n timestamp: Date.now(),\n resolve,\n reject,\n };\n\n this.taskQueue.push(task);\n this.processQueue();\n });\n }\n\n public getStats() {\n return {\n total: this.workers.length,\n active: this.activeJobs.size,\n idle: this.availableWorkers.size,\n queued: this.taskQueue.length,\n };\n }\n\n public destroy(): void {\n for (const worker of this.workers) {\n worker.terminate();\n }\n this.workers = [];\n this.availableWorkers.clear();\n this.taskQueue = [];\n this.activeJobs.clear();\n }\n}\n","/**\n * @fileoverview Offscreen rendering plugin (skeleton with stats + feature detection)\n * @module plugins/offscreen\n */\n\nimport type {\n PluginOffscreenConfig,\n OffscreenAPI,\n OffscreenStats,\n} from \"./types\";\nimport type { ChartPlugin, PluginContext, PluginManifest } from \"../types\";\n\nconst manifest: PluginManifest = {\n name: \"velo-plot-offscreen\",\n version: \"1.0.0\",\n description: \"Offscreen rendering support with worker-ready scaffolding\",\n provides: [\"performance\", \"offscreen\"],\n tags: [\"performance\", \"offscreen\", \"worker\"],\n};\n\nconst DEFAULT_CONFIG: Required<PluginOffscreenConfig> = {\n enabled: false,\n mode: \"auto\",\n workerPool: 1,\n transfer: \"offscreen\",\n fallback: \"main-thread\",\n debug: false,\n};\n\nimport { WorkerPool } from \"./pool\";\n\nexport function PluginOffscreen(\n userConfig: Partial<PluginOffscreenConfig> = {}\n): ChartPlugin<PluginOffscreenConfig> {\n const config = { ...DEFAULT_CONFIG, ...userConfig };\n let ctx: PluginContext | null = null;\n let pool: WorkerPool | null = null;\n let stats: OffscreenStats = {\n enabled: config.enabled,\n frames: 0,\n lastFrameTime: 0,\n lastFrameTimestamp: 0,\n };\n\n function log(message: string, ...args: unknown[]) {\n if (config.debug && ctx) {\n ctx.log.info(`[Offscreen] ${message}`, ...args);\n }\n }\n\n function isSupported(): boolean {\n return typeof (globalThis as any).OffscreenCanvas !== \"undefined\";\n }\n\n function enable(): void {\n if (!isSupported()) {\n log(\"OffscreenCanvas not supported. Falling back to main thread.\");\n if (config.fallback === \"disable\") {\n stats.enabled = false;\n return;\n }\n }\n \n if (!pool) {\n pool = new WorkerPool(config.workerPool || 1);\n }\n \n stats.enabled = true;\n config.enabled = true;\n }\n\n function disable(): void {\n if (pool) {\n pool.destroy();\n pool = null;\n }\n stats.enabled = false;\n config.enabled = false;\n }\n\n function updateConfig(newConfig: Partial<PluginOffscreenConfig>): void {\n Object.assign(config, newConfig);\n if (config.enabled) enable();\n else disable();\n stats.enabled = !!config.enabled;\n }\n\n function getStats(): OffscreenStats {\n const poolStats = pool?.getStats();\n return { \n ...stats,\n activeWorkers: poolStats?.active || 0,\n queuedTasks: poolStats?.queued || 0\n } as any;\n }\n\n function flush(): void {\n ctx?.requestRender();\n }\n\n const api: OffscreenAPI & Record<string, unknown> = {\n enable,\n disable,\n isEnabled: () => stats.enabled,\n updateConfig,\n getStats,\n flush,\n };\n\n return {\n manifest,\n onInit(pluginCtx: PluginContext) {\n ctx = pluginCtx;\n (ctx.chart as any).offscreen = api;\n if (config.enabled) enable();\n log(`Initialized (pool=${config.workerPool})`);\n },\n onDestroy(pluginCtx: PluginContext) {\n disable();\n delete (pluginCtx.chart as any).offscreen;\n ctx = null;\n },\n onAfterRender(_ctx, event) {\n stats.frames += 1;\n stats.lastFrameTime = event.renderTime;\n stats.lastFrameTimestamp = event.timestamp;\n \n if (config.enabled && pool) {\n // In a real implementation, we would offload the next render piece here\n // For now, we just track that we could have used the pool\n }\n },\n api,\n };\n}\n\nexport default PluginOffscreen;\n\n// Type exports\nexport type {\n PluginOffscreenConfig,\n OffscreenAPI,\n OffscreenStats,\n OffscreenMode,\n OffscreenTransferMode,\n OffscreenFallbackMode,\n} from \"./types\";\n"],"names":["WorkerPool","size","__publicField","workerCode","blob","workerUrl","i","worker","e","error","workerIndex","event","type","taskId","imageData","task","wIndex","t","a","b","priority","resolve","reject","manifest","DEFAULT_CONFIG","PluginOffscreen","userConfig","config","ctx","pool","stats","log","message","args","isSupported","enable","disable","updateConfig","newConfig","getStats","poolStats","flush","api","pluginCtx","_ctx"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"offscreen.js","sources":["../../src/plugins/offscreen/pool.ts","../../src/plugins/offscreen/index.ts"],"sourcesContent":["/**\n * @fileoverview Worker Pool Manager for Offscreen Rendering\n * @module plugins/offscreen/pool\n */\n\nexport interface WorkerTask {\n id: string;\n priority: number;\n timestamp: number;\n resolve: (value: ImageBitmap) => void;\n reject: (error: Error) => void;\n}\n\nexport class WorkerPool {\n private workers: Worker[] = [];\n private availableWorkers: Set<number> = new Set();\n private taskQueue: WorkerTask[] = [];\n private activeJobs: Map<string, number> = new Map(); // taskId => workerIndex\n\n constructor(private size: number) {\n this.initialize();\n }\n\n private initialize(): void {\n const workerCode = `\n // Simple offscreen worker\n self.onmessage = (e) => {\n const { type, width, height, dpr } = e.data;\n \n if (type === 'render') {\n // Echo back - actual rendering logic would go here\n self.postMessage({ type: 'response', taskId: e.data.taskId });\n }\n };\n `;\n\n const blob = new Blob([workerCode], { type: 'application/javascript' });\n const workerUrl = URL.createObjectURL(blob);\n\n for (let i = 0; i < this.size; i++) {\n try {\n const worker = new Worker(workerUrl);\n worker.onmessage = (e) => this.handleWorkerMessage(i, e);\n worker.onerror = (e) => this.handleWorkerError(i, e);\n this.workers.push(worker);\n this.availableWorkers.add(i);\n } catch (error) {\n console.error(`Failed to create worker ${i}:`, error);\n }\n }\n\n URL.revokeObjectURL(workerUrl);\n }\n\n private handleWorkerMessage(workerIndex: number, event: MessageEvent): void {\n const { type, taskId, imageData, error } = event.data;\n\n if (type === 'response') {\n const task = this.findTask(taskId);\n if (task) {\n if (error) {\n task.reject(new Error(error));\n } else if (imageData) {\n task.resolve(imageData);\n }\n this.activeJobs.delete(taskId);\n this.availableWorkers.add(workerIndex);\n this.processQueue();\n }\n }\n }\n\n private handleWorkerError(workerIndex: number, error: ErrorEvent): void {\n console.error(`Worker ${workerIndex} error:`, error);\n // Find and reject any active task for this worker\n for (const [taskId, wIndex] of this.activeJobs.entries()) {\n if (wIndex === workerIndex) {\n const task = this.findTask(taskId);\n if (task) {\n task.reject(new Error(`Worker error: ${error.message}`));\n this.activeJobs.delete(taskId);\n }\n }\n }\n this.availableWorkers.add(workerIndex);\n this.processQueue();\n }\n\n private findTask(taskId: string): WorkerTask | undefined {\n return this.taskQueue.find(t => t.id === taskId);\n }\n\n private processQueue(): void {\n while (this.availableWorkers.size > 0 && this.taskQueue.length > 0) {\n // Sort by priority and timestamp\n this.taskQueue.sort((a, b) => {\n if (a.priority !== b.priority) return b.priority - a.priority;\n return a.timestamp - b.timestamp;\n });\n\n const task = this.taskQueue.shift();\n if (!task) break;\n\n const workerIndex = Array.from(this.availableWorkers)[0];\n this.availableWorkers.delete(workerIndex);\n this.activeJobs.set(task.id, workerIndex);\n\n // Send task to worker\n this.workers[workerIndex].postMessage({\n type: 'render',\n taskId: task.id,\n });\n }\n }\n\n public submit(priority: number = 0): Promise<ImageBitmap> {\n return new Promise((resolve, reject) => {\n const task: WorkerTask = {\n id: Math.random().toString(36).substring(7),\n priority,\n timestamp: Date.now(),\n resolve,\n reject,\n };\n\n this.taskQueue.push(task);\n this.processQueue();\n });\n }\n\n public getStats() {\n return {\n total: this.workers.length,\n active: this.activeJobs.size,\n idle: this.availableWorkers.size,\n queued: this.taskQueue.length,\n };\n }\n\n public destroy(): void {\n for (const worker of this.workers) {\n worker.terminate();\n }\n this.workers = [];\n this.availableWorkers.clear();\n this.taskQueue = [];\n this.activeJobs.clear();\n }\n}\n","/**\n * @fileoverview Offscreen rendering plugin (skeleton with stats + feature detection)\n * @module plugins/offscreen\n */\n\nimport type {\n PluginOffscreenConfig,\n OffscreenAPI,\n OffscreenStats,\n} from \"./types\";\nimport type { ChartPlugin, PluginContext, PluginManifest } from \"../types\";\n\nconst manifest: PluginManifest = {\n name: \"velo-plot-offscreen\",\n version: \"1.0.0\",\n description: \"Offscreen rendering support with worker-ready scaffolding\",\n provides: [\"performance\", \"offscreen\"],\n tags: [\"performance\", \"offscreen\", \"worker\"],\n};\n\nconst DEFAULT_CONFIG: Required<PluginOffscreenConfig> = {\n enabled: false,\n mode: \"auto\",\n workerPool: 1,\n transfer: \"offscreen\",\n fallback: \"main-thread\",\n debug: false,\n};\n\nimport { WorkerPool } from \"./pool\";\n\nexport function PluginOffscreen(\n userConfig: Partial<PluginOffscreenConfig> = {}\n): ChartPlugin<PluginOffscreenConfig> {\n const config = { ...DEFAULT_CONFIG, ...userConfig };\n let ctx: PluginContext | null = null;\n let pool: WorkerPool | null = null;\n const stats: OffscreenStats = {\n enabled: config.enabled,\n frames: 0,\n lastFrameTime: 0,\n lastFrameTimestamp: 0,\n };\n\n function log(message: string, ...args: unknown[]) {\n if (config.debug && ctx) {\n ctx.log.info(`[Offscreen] ${message}`, ...args);\n }\n }\n\n function isSupported(): boolean {\n return typeof (globalThis as any).OffscreenCanvas !== \"undefined\";\n }\n\n function enable(): void {\n if (!isSupported()) {\n log(\"OffscreenCanvas not supported. Falling back to main thread.\");\n if (config.fallback === \"disable\") {\n stats.enabled = false;\n return;\n }\n }\n \n if (!pool) {\n pool = new WorkerPool(config.workerPool || 1);\n }\n \n stats.enabled = true;\n config.enabled = true;\n }\n\n function disable(): void {\n if (pool) {\n pool.destroy();\n pool = null;\n }\n stats.enabled = false;\n config.enabled = false;\n }\n\n function updateConfig(newConfig: Partial<PluginOffscreenConfig>): void {\n Object.assign(config, newConfig);\n if (config.enabled) enable();\n else disable();\n stats.enabled = !!config.enabled;\n }\n\n function getStats(): OffscreenStats {\n const poolStats = pool?.getStats();\n return { \n ...stats,\n activeWorkers: poolStats?.active || 0,\n queuedTasks: poolStats?.queued || 0\n } as any;\n }\n\n function flush(): void {\n ctx?.requestRender();\n }\n\n const api: OffscreenAPI & Record<string, unknown> = {\n enable,\n disable,\n isEnabled: () => stats.enabled,\n updateConfig,\n getStats,\n flush,\n };\n\n return {\n manifest,\n onInit(pluginCtx: PluginContext) {\n ctx = pluginCtx;\n (ctx.chart as any).offscreen = api;\n if (config.enabled) enable();\n log(`Initialized (pool=${config.workerPool})`);\n },\n onDestroy(pluginCtx: PluginContext) {\n disable();\n delete (pluginCtx.chart as any).offscreen;\n ctx = null;\n },\n onAfterRender(_ctx, event) {\n stats.frames += 1;\n stats.lastFrameTime = event.renderTime;\n stats.lastFrameTimestamp = event.timestamp;\n \n if (config.enabled && pool) {\n // In a real implementation, we would offload the next render piece here\n // For now, we just track that we could have used the pool\n }\n },\n api,\n };\n}\n\nexport default PluginOffscreen;\n\n// Type exports\nexport type {\n PluginOffscreenConfig,\n OffscreenAPI,\n OffscreenStats,\n OffscreenMode,\n OffscreenTransferMode,\n OffscreenFallbackMode,\n} from \"./types\";\n"],"names":["WorkerPool","size","__publicField","workerCode","blob","workerUrl","i","worker","e","error","workerIndex","event","type","taskId","imageData","task","wIndex","t","a","b","priority","resolve","reject","manifest","DEFAULT_CONFIG","PluginOffscreen","userConfig","config","ctx","pool","stats","log","message","args","isSupported","enable","disable","updateConfig","newConfig","getStats","poolStats","flush","api","pluginCtx","_ctx"],"mappings":"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"}
|
|
@@ -31,10 +31,21 @@ export interface PluginRadarConfig {
|
|
|
31
31
|
lineDash?: number[];
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
|
+
export interface RadarSVGExportData {
|
|
35
|
+
categories: string[];
|
|
36
|
+
maxValue: number;
|
|
37
|
+
gridLevels: number;
|
|
38
|
+
showLabels: boolean;
|
|
39
|
+
labelStyle?: PluginRadarConfig["labelStyle"];
|
|
40
|
+
gridStyle?: PluginRadarConfig["gridStyle"];
|
|
41
|
+
series: RadarSeriesData[];
|
|
42
|
+
}
|
|
34
43
|
export interface RadarAPI {
|
|
35
44
|
addSeries(data: RadarSeriesData): string;
|
|
36
45
|
removeSeries(id: string): boolean;
|
|
37
46
|
updateSeries(id: string, points: RadarPoint[]): boolean;
|
|
38
47
|
setCategories(categories: string[]): void;
|
|
39
48
|
setMaxValue(value: number): void;
|
|
49
|
+
/** Snapshot for SVG live renderer / export pipeline */
|
|
50
|
+
getSVGExportData(): RadarSVGExportData | null;
|
|
40
51
|
}
|
package/dist/plugins/radar.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
const
|
|
1
|
+
const T = {
|
|
2
2
|
name: "velo-plot-radar",
|
|
3
3
|
version: "1.0.0",
|
|
4
4
|
description: "Advanced Radar/Spider Charts for velo-plot",
|
|
5
5
|
provides: ["radar", "spider-chart"],
|
|
6
6
|
tags: ["radar", "visualization", "comparison"]
|
|
7
|
-
},
|
|
7
|
+
}, V = {
|
|
8
8
|
categories: [],
|
|
9
9
|
maxValue: 100,
|
|
10
10
|
minValue: 0,
|
|
@@ -21,83 +21,94 @@ const D = {
|
|
|
21
21
|
lineDash: []
|
|
22
22
|
}
|
|
23
23
|
};
|
|
24
|
-
function
|
|
25
|
-
const
|
|
26
|
-
let
|
|
27
|
-
const
|
|
28
|
-
function
|
|
29
|
-
var
|
|
30
|
-
const { render: h } =
|
|
24
|
+
function q(A = {}) {
|
|
25
|
+
const a = { ...V, ...A };
|
|
26
|
+
let r = null;
|
|
27
|
+
const f = /* @__PURE__ */ new Map();
|
|
28
|
+
function D(i) {
|
|
29
|
+
var b, M, y, x, P, R;
|
|
30
|
+
const { render: h } = i, { ctx2d: e, plotArea: d } = h;
|
|
31
31
|
if (!e) return;
|
|
32
|
-
const
|
|
33
|
-
if (
|
|
34
|
-
const
|
|
35
|
-
e.save(), e.strokeStyle = ((
|
|
36
|
-
for (let
|
|
37
|
-
const
|
|
32
|
+
const g = d.x + d.width / 2, u = d.y + d.height / 2, S = Math.min(d.width, d.height) / 2 * 0.8, m = a.categories.length;
|
|
33
|
+
if (m === 0) return;
|
|
34
|
+
const v = 2 * Math.PI / m;
|
|
35
|
+
e.save(), e.strokeStyle = ((b = a.gridStyle) == null ? void 0 : b.color) || "rgba(255, 255, 255, 0.1)", e.lineWidth = ((M = a.gridStyle) == null ? void 0 : M.width) || 1, (y = a.gridStyle) != null && y.lineDash && a.gridStyle.lineDash.length > 0 && e.setLineDash(a.gridStyle.lineDash);
|
|
36
|
+
for (let n = 1; n <= a.gridLevels; n++) {
|
|
37
|
+
const s = n / a.gridLevels * S;
|
|
38
38
|
e.beginPath();
|
|
39
|
-
for (let t = 0; t <
|
|
40
|
-
const l = t *
|
|
41
|
-
t === 0 ? e.moveTo(
|
|
39
|
+
for (let t = 0; t < m; t++) {
|
|
40
|
+
const l = t * v - Math.PI / 2, o = g + s * Math.cos(l), c = u + s * Math.sin(l);
|
|
41
|
+
t === 0 ? e.moveTo(o, c) : e.lineTo(o, c);
|
|
42
42
|
}
|
|
43
43
|
e.closePath(), e.stroke();
|
|
44
44
|
}
|
|
45
45
|
e.setLineDash([]);
|
|
46
|
-
for (let
|
|
47
|
-
const
|
|
48
|
-
if (e.beginPath(), e.moveTo(
|
|
49
|
-
const
|
|
50
|
-
e.fillStyle = ((x =
|
|
46
|
+
for (let n = 0; n < m; n++) {
|
|
47
|
+
const s = n * v - Math.PI / 2, t = g + S * Math.cos(s), l = u + S * Math.sin(s);
|
|
48
|
+
if (e.beginPath(), e.moveTo(g, u), e.lineTo(t, l), e.stroke(), a.showLabels) {
|
|
49
|
+
const o = S + 25, c = g + o * Math.cos(s), p = u + o * Math.sin(s);
|
|
50
|
+
e.fillStyle = ((x = a.labelStyle) == null ? void 0 : x.color) || "#94a3b8", e.font = `${((P = a.labelStyle) == null ? void 0 : P.fontSize) || 12}px ${((R = a.labelStyle) == null ? void 0 : R.fontFamily) || "sans-serif"}`, e.textAlign = Math.abs(Math.cos(s)) < 0.1 ? "center" : Math.cos(s) > 0 ? "left" : "right", e.textBaseline = Math.abs(Math.sin(s)) < 0.1 ? "middle" : Math.sin(s) > 0 ? "top" : "bottom", e.fillText(a.categories[n], c, p);
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
|
-
|
|
54
|
-
const { points:
|
|
55
|
-
if (
|
|
53
|
+
f.forEach((n) => {
|
|
54
|
+
const { points: s, style: t } = n;
|
|
55
|
+
if (s.length === 0) return;
|
|
56
56
|
const l = [];
|
|
57
|
-
|
|
58
|
-
const
|
|
57
|
+
a.categories.forEach((o, c) => {
|
|
58
|
+
const p = s.find((I) => I.category === o), L = (p ? p.value : 0) / a.maxValue * S, w = c * v - Math.PI / 2;
|
|
59
59
|
l.push({
|
|
60
|
-
x:
|
|
61
|
-
y:
|
|
60
|
+
x: g + L * Math.cos(w),
|
|
61
|
+
y: u + L * Math.sin(w)
|
|
62
62
|
});
|
|
63
|
-
}), e.beginPath(), l.forEach((
|
|
64
|
-
c === 0 ? e.moveTo(
|
|
65
|
-
}), e.closePath(), e.fillStyle = (t == null ? void 0 : t.fillColor) || (t != null && t.color ? `${t.color}33` : "rgba(0, 242, 255, 0.2)"), e.fill(), e.strokeStyle = (t == null ? void 0 : t.color) || "#00f2ff", e.lineWidth = (t == null ? void 0 : t.width) || 2, e.globalAlpha = (t == null ? void 0 : t.opacity) || 1, e.stroke(), ((t == null ? void 0 : t.pointSize) || 0) > 0 && (e.fillStyle = (t == null ? void 0 : t.color) || "#00f2ff", l.forEach((
|
|
66
|
-
e.beginPath(), e.arc(
|
|
63
|
+
}), e.beginPath(), l.forEach((o, c) => {
|
|
64
|
+
c === 0 ? e.moveTo(o.x, o.y) : e.lineTo(o.x, o.y);
|
|
65
|
+
}), e.closePath(), e.fillStyle = (t == null ? void 0 : t.fillColor) || (t != null && t.color ? `${t.color}33` : "rgba(0, 242, 255, 0.2)"), e.fill(), e.strokeStyle = (t == null ? void 0 : t.color) || "#00f2ff", e.lineWidth = (t == null ? void 0 : t.width) || 2, e.globalAlpha = (t == null ? void 0 : t.opacity) || 1, e.stroke(), ((t == null ? void 0 : t.pointSize) || 0) > 0 && (e.fillStyle = (t == null ? void 0 : t.color) || "#00f2ff", l.forEach((o) => {
|
|
66
|
+
e.beginPath(), e.arc(o.x, o.y, t.pointSize / 2, 0, Math.PI * 2), e.fill();
|
|
67
67
|
}));
|
|
68
68
|
}), e.restore();
|
|
69
69
|
}
|
|
70
70
|
return {
|
|
71
|
-
manifest:
|
|
72
|
-
onInit(
|
|
73
|
-
|
|
71
|
+
manifest: T,
|
|
72
|
+
onInit(i) {
|
|
73
|
+
r = i, r.chart.updateXAxis({ visible: !1, min: -1.2, max: 1.2 }), r.chart.updateYAxis("default", { visible: !1, min: -1.2, max: 1.2 });
|
|
74
74
|
},
|
|
75
|
-
onRenderOverlay(
|
|
76
|
-
|
|
75
|
+
onRenderOverlay(i, h) {
|
|
76
|
+
i.chart.getActiveRenderer() !== "svg" && D(i);
|
|
77
77
|
},
|
|
78
78
|
api: {
|
|
79
|
-
addSeries(
|
|
80
|
-
return
|
|
79
|
+
addSeries(i) {
|
|
80
|
+
return f.set(i.id, i), r == null || r.requestRender(), i.id;
|
|
81
81
|
},
|
|
82
|
-
removeSeries(
|
|
83
|
-
const h =
|
|
84
|
-
return h && (
|
|
82
|
+
removeSeries(i) {
|
|
83
|
+
const h = f.delete(i);
|
|
84
|
+
return h && (r == null || r.requestRender()), h;
|
|
85
85
|
},
|
|
86
|
-
updateSeries(
|
|
87
|
-
const e =
|
|
88
|
-
return e ? (e.points = h,
|
|
86
|
+
updateSeries(i, h) {
|
|
87
|
+
const e = f.get(i);
|
|
88
|
+
return e ? (e.points = h, r == null || r.requestRender(), !0) : !1;
|
|
89
89
|
},
|
|
90
|
-
setCategories(
|
|
91
|
-
|
|
90
|
+
setCategories(i) {
|
|
91
|
+
a.categories = i, r == null || r.requestRender();
|
|
92
92
|
},
|
|
93
|
-
setMaxValue(
|
|
94
|
-
|
|
93
|
+
setMaxValue(i) {
|
|
94
|
+
a.maxValue = i, r == null || r.requestRender();
|
|
95
|
+
},
|
|
96
|
+
getSVGExportData() {
|
|
97
|
+
return a.categories.length === 0 ? null : {
|
|
98
|
+
categories: [...a.categories],
|
|
99
|
+
maxValue: a.maxValue,
|
|
100
|
+
gridLevels: a.gridLevels,
|
|
101
|
+
showLabels: a.showLabels,
|
|
102
|
+
labelStyle: a.labelStyle,
|
|
103
|
+
gridStyle: a.gridStyle,
|
|
104
|
+
series: Array.from(f.values())
|
|
105
|
+
};
|
|
95
106
|
}
|
|
96
107
|
}
|
|
97
108
|
};
|
|
98
109
|
}
|
|
99
110
|
export {
|
|
100
|
-
|
|
101
|
-
|
|
111
|
+
q as PluginRadar,
|
|
112
|
+
q as default
|
|
102
113
|
};
|
|
103
114
|
//# sourceMappingURL=radar.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"radar.js","sources":["../../src/plugins/radar/index.ts"],"sourcesContent":["import type { \n PluginRadarConfig, \n RadarAPI, \n RadarSeriesData, \n RadarPoint \n} from './types';\nimport type { \n PluginManifest, \n ChartPlugin, \n PluginContext,\n AfterRenderEvent\n} from '../types';\n\nconst manifestRadar: PluginManifest = {\n name: \"velo-plot-radar\",\n version: \"1.0.0\",\n description: \"Advanced Radar/Spider Charts for velo-plot\",\n provides: [\"radar\", \"spider-chart\"],\n tags: [\"radar\", \"visualization\", \"comparison\"],\n};\n\nconst DEFAULT_CONFIG: Required<PluginRadarConfig> = {\n categories: [],\n maxValue: 100,\n minValue: 0,\n gridLevels: 5,\n showLabels: true,\n labelStyle: {\n fontSize: 12,\n color: '#94a3b8',\n fontFamily: 'Inter, system-ui, sans-serif'\n },\n gridStyle: {\n color: 'rgba(255, 255, 255, 0.1)',\n width: 1,\n lineDash: []\n }\n};\n\nexport function PluginRadar(\n userConfig: Partial<PluginRadarConfig> = {}\n): ChartPlugin<PluginRadarConfig> {\n const config = { ...DEFAULT_CONFIG, ...userConfig };\n let ctx: PluginContext | null = null;\n const radarSeries = new Map<string, RadarSeriesData>();\n\n // ============================================\n // Drawing Logic\n // ============================================\n\n function drawRadar(pCtx: PluginContext) {\n const { render } = pCtx;\n const { ctx2d, plotArea } = render;\n\n if (!ctx2d) return;\n\n const centerX = plotArea.x + plotArea.width / 2;\n const centerY = plotArea.y + plotArea.height / 2;\n const maxRadiusPixels = Math.min(plotArea.width, plotArea.height) / 2 * 0.8;\n const numCategories = config.categories.length;\n \n if (numCategories === 0) return;\n const angleStep = (2 * Math.PI) / numCategories;\n\n ctx2d.save();\n \n // 1. Draw Grid (Levels)\n ctx2d.strokeStyle = config.gridStyle?.color || 'rgba(255, 255, 255, 0.1)';\n ctx2d.lineWidth = config.gridStyle?.width || 1;\n if (config.gridStyle?.lineDash && config.gridStyle.lineDash.length > 0) {\n ctx2d.setLineDash(config.gridStyle.lineDash);\n }\n\n for (let level = 1; level <= config.gridLevels; level++) {\n const radius = (level / config.gridLevels) * maxRadiusPixels;\n ctx2d.beginPath();\n for (let i = 0; i < numCategories; i++) {\n const angle = i * angleStep - Math.PI / 2;\n const px = centerX + radius * Math.cos(angle);\n const py = centerY + radius * Math.sin(angle);\n if (i === 0) ctx2d.moveTo(px, py);\n else ctx2d.lineTo(px, py);\n }\n ctx2d.closePath();\n ctx2d.stroke();\n }\n\n // 2. Draw Spokes and Labels\n ctx2d.setLineDash([]);\n for (let i = 0; i < numCategories; i++) {\n const angle = i * angleStep - Math.PI / 2;\n const px = centerX + maxRadiusPixels * Math.cos(angle);\n const py = centerY + maxRadiusPixels * Math.sin(angle);\n \n ctx2d.beginPath();\n ctx2d.moveTo(centerX, centerY);\n ctx2d.lineTo(px, py);\n ctx2d.stroke();\n\n if (config.showLabels) {\n const labelRadius = maxRadiusPixels + 25;\n const lx = centerX + labelRadius * Math.cos(angle);\n const ly = centerY + labelRadius * Math.sin(angle);\n \n ctx2d.fillStyle = config.labelStyle?.color || '#94a3b8';\n ctx2d.font = `${config.labelStyle?.fontSize || 12}px ${config.labelStyle?.fontFamily || 'sans-serif'}`;\n ctx2d.textAlign = Math.abs(Math.cos(angle)) < 0.1 ? \"center\" : (Math.cos(angle) > 0 ? \"left\" : \"right\");\n ctx2d.textBaseline = Math.abs(Math.sin(angle)) < 0.1 ? \"middle\" : (Math.sin(angle) > 0 ? \"top\" : \"bottom\");\n ctx2d.fillText(config.categories[i], lx, ly);\n }\n }\n\n // 3. Draw Radar Series\n radarSeries.forEach((series) => {\n const { points, style } = series;\n if (points.length === 0) return;\n\n const pathPoints: { x: number, y: number }[] = [];\n \n config.categories.forEach((cat, idx) => {\n const point = points.find(p => p.category === cat);\n const val = point ? point.value : 0;\n const radius = (val / config.maxValue) * maxRadiusPixels;\n const angle = idx * angleStep - Math.PI / 2;\n \n pathPoints.push({\n x: centerX + radius * Math.cos(angle),\n y: centerY + radius * Math.sin(angle)\n });\n });\n\n ctx2d.beginPath();\n pathPoints.forEach((p, i) => {\n if (i === 0) ctx2d.moveTo(p.x, p.y);\n else ctx2d.lineTo(p.x, p.y);\n });\n ctx2d.closePath();\n \n ctx2d.fillStyle = style?.fillColor || (style?.color ? `${style.color}33` : 'rgba(0, 242, 255, 0.2)');\n ctx2d.fill();\n \n ctx2d.strokeStyle = style?.color || '#00f2ff';\n ctx2d.lineWidth = style?.width || 2;\n ctx2d.globalAlpha = style?.opacity || 1;\n ctx2d.stroke();\n\n if ((style?.pointSize || 0) > 0) {\n ctx2d.fillStyle = style?.color || '#00f2ff';\n pathPoints.forEach(p => {\n ctx2d.beginPath();\n ctx2d.arc(p.x, p.y, style!.pointSize! / 2, 0, Math.PI * 2);\n ctx2d.fill();\n });\n }\n });\n\n ctx2d.restore();\n }\n\n // ============================================\n // Plugin API\n // ============================================\n\n const api: RadarAPI & Record<string, unknown> = {\n addSeries(data: RadarSeriesData) {\n radarSeries.set(data.id, data);\n ctx?.requestRender();\n return data.id;\n },\n removeSeries(id: string) {\n const res = radarSeries.delete(id);\n if (res) ctx?.requestRender();\n return res;\n },\n updateSeries(id: string, points: RadarPoint[]) {\n const series = radarSeries.get(id);\n if (series) {\n series.points = points;\n ctx?.requestRender();\n return true;\n }\n return false;\n },\n setCategories(categories: string[]) {\n config.categories = categories;\n ctx?.requestRender();\n },\n setMaxValue(value: number) {\n config.maxValue = value;\n ctx?.requestRender();\n }\n };\n\n return {\n manifest: manifestRadar,\n\n onInit(c: PluginContext) {\n ctx = c;\n // Setup the chart for Radar (centered origin, fixed bounds)\n ctx.chart.updateXAxis({ visible: false, min: -1.2, max: 1.2 });\n ctx.chart.updateYAxis('default', { visible: false, min: -1.2, max: 1.2 });\n },\n\n onRenderOverlay(pCtx: PluginContext, _event: AfterRenderEvent) {\n drawRadar(pCtx);\n },\n\n api\n };\n}\n\nexport default PluginRadar;\n\nexport type { \n PluginRadarConfig, \n RadarAPI, \n RadarSeriesData, \n RadarPoint \n} from './types';\n"],"names":["manifestRadar","DEFAULT_CONFIG","PluginRadar","userConfig","config","ctx","radarSeries","drawRadar","pCtx","_a","_b","_c","_d","_e","_f","render","ctx2d","plotArea","centerX","centerY","maxRadiusPixels","numCategories","angleStep","level","radius","i","angle","px","py","labelRadius","lx","ly","series","points","style","pathPoints","cat","idx","point","p","c","_event","data","id","res","categories","value"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"radar.js","sources":["../../src/plugins/radar/index.ts"],"sourcesContent":["import type { \n PluginRadarConfig, \n RadarAPI, \n RadarSeriesData, \n RadarPoint \n} from './types';\nimport type { \n PluginManifest, \n ChartPlugin, \n PluginContext,\n AfterRenderEvent\n} from '../types';\n\nconst manifestRadar: PluginManifest = {\n name: \"velo-plot-radar\",\n version: \"1.0.0\",\n description: \"Advanced Radar/Spider Charts for velo-plot\",\n provides: [\"radar\", \"spider-chart\"],\n tags: [\"radar\", \"visualization\", \"comparison\"],\n};\n\nconst DEFAULT_CONFIG: Required<PluginRadarConfig> = {\n categories: [],\n maxValue: 100,\n minValue: 0,\n gridLevels: 5,\n showLabels: true,\n labelStyle: {\n fontSize: 12,\n color: '#94a3b8',\n fontFamily: 'Inter, system-ui, sans-serif'\n },\n gridStyle: {\n color: 'rgba(255, 255, 255, 0.1)',\n width: 1,\n lineDash: []\n }\n};\n\nexport function PluginRadar(\n userConfig: Partial<PluginRadarConfig> = {}\n): ChartPlugin<PluginRadarConfig> {\n const config = { ...DEFAULT_CONFIG, ...userConfig };\n let ctx: PluginContext | null = null;\n const radarSeries = new Map<string, RadarSeriesData>();\n\n // ============================================\n // Drawing Logic\n // ============================================\n\n function drawRadar(pCtx: PluginContext) {\n const { render } = pCtx;\n const { ctx2d, plotArea } = render;\n\n if (!ctx2d) return;\n\n const centerX = plotArea.x + plotArea.width / 2;\n const centerY = plotArea.y + plotArea.height / 2;\n const maxRadiusPixels = Math.min(plotArea.width, plotArea.height) / 2 * 0.8;\n const numCategories = config.categories.length;\n \n if (numCategories === 0) return;\n const angleStep = (2 * Math.PI) / numCategories;\n\n ctx2d.save();\n \n // 1. Draw Grid (Levels)\n ctx2d.strokeStyle = config.gridStyle?.color || 'rgba(255, 255, 255, 0.1)';\n ctx2d.lineWidth = config.gridStyle?.width || 1;\n if (config.gridStyle?.lineDash && config.gridStyle.lineDash.length > 0) {\n ctx2d.setLineDash(config.gridStyle.lineDash);\n }\n\n for (let level = 1; level <= config.gridLevels; level++) {\n const radius = (level / config.gridLevels) * maxRadiusPixels;\n ctx2d.beginPath();\n for (let i = 0; i < numCategories; i++) {\n const angle = i * angleStep - Math.PI / 2;\n const px = centerX + radius * Math.cos(angle);\n const py = centerY + radius * Math.sin(angle);\n if (i === 0) ctx2d.moveTo(px, py);\n else ctx2d.lineTo(px, py);\n }\n ctx2d.closePath();\n ctx2d.stroke();\n }\n\n // 2. Draw Spokes and Labels\n ctx2d.setLineDash([]);\n for (let i = 0; i < numCategories; i++) {\n const angle = i * angleStep - Math.PI / 2;\n const px = centerX + maxRadiusPixels * Math.cos(angle);\n const py = centerY + maxRadiusPixels * Math.sin(angle);\n \n ctx2d.beginPath();\n ctx2d.moveTo(centerX, centerY);\n ctx2d.lineTo(px, py);\n ctx2d.stroke();\n\n if (config.showLabels) {\n const labelRadius = maxRadiusPixels + 25;\n const lx = centerX + labelRadius * Math.cos(angle);\n const ly = centerY + labelRadius * Math.sin(angle);\n \n ctx2d.fillStyle = config.labelStyle?.color || '#94a3b8';\n ctx2d.font = `${config.labelStyle?.fontSize || 12}px ${config.labelStyle?.fontFamily || 'sans-serif'}`;\n ctx2d.textAlign = Math.abs(Math.cos(angle)) < 0.1 ? \"center\" : (Math.cos(angle) > 0 ? \"left\" : \"right\");\n ctx2d.textBaseline = Math.abs(Math.sin(angle)) < 0.1 ? \"middle\" : (Math.sin(angle) > 0 ? \"top\" : \"bottom\");\n ctx2d.fillText(config.categories[i], lx, ly);\n }\n }\n\n // 3. Draw Radar Series\n radarSeries.forEach((series) => {\n const { points, style } = series;\n if (points.length === 0) return;\n\n const pathPoints: { x: number, y: number }[] = [];\n \n config.categories.forEach((cat, idx) => {\n const point = points.find(p => p.category === cat);\n const val = point ? point.value : 0;\n const radius = (val / config.maxValue) * maxRadiusPixels;\n const angle = idx * angleStep - Math.PI / 2;\n \n pathPoints.push({\n x: centerX + radius * Math.cos(angle),\n y: centerY + radius * Math.sin(angle)\n });\n });\n\n ctx2d.beginPath();\n pathPoints.forEach((p, i) => {\n if (i === 0) ctx2d.moveTo(p.x, p.y);\n else ctx2d.lineTo(p.x, p.y);\n });\n ctx2d.closePath();\n \n ctx2d.fillStyle = style?.fillColor || (style?.color ? `${style.color}33` : 'rgba(0, 242, 255, 0.2)');\n ctx2d.fill();\n \n ctx2d.strokeStyle = style?.color || '#00f2ff';\n ctx2d.lineWidth = style?.width || 2;\n ctx2d.globalAlpha = style?.opacity || 1;\n ctx2d.stroke();\n\n if ((style?.pointSize || 0) > 0) {\n ctx2d.fillStyle = style?.color || '#00f2ff';\n pathPoints.forEach(p => {\n ctx2d.beginPath();\n ctx2d.arc(p.x, p.y, style!.pointSize! / 2, 0, Math.PI * 2);\n ctx2d.fill();\n });\n }\n });\n\n ctx2d.restore();\n }\n\n // ============================================\n // Plugin API\n // ============================================\n\n const api: RadarAPI & Record<string, unknown> = {\n addSeries(data: RadarSeriesData) {\n radarSeries.set(data.id, data);\n ctx?.requestRender();\n return data.id;\n },\n removeSeries(id: string) {\n const res = radarSeries.delete(id);\n if (res) ctx?.requestRender();\n return res;\n },\n updateSeries(id: string, points: RadarPoint[]) {\n const series = radarSeries.get(id);\n if (series) {\n series.points = points;\n ctx?.requestRender();\n return true;\n }\n return false;\n },\n setCategories(categories: string[]) {\n config.categories = categories;\n ctx?.requestRender();\n },\n setMaxValue(value: number) {\n config.maxValue = value;\n ctx?.requestRender();\n },\n getSVGExportData() {\n if (config.categories.length === 0) return null;\n return {\n categories: [...config.categories],\n maxValue: config.maxValue,\n gridLevels: config.gridLevels,\n showLabels: config.showLabels,\n labelStyle: config.labelStyle,\n gridStyle: config.gridStyle,\n series: Array.from(radarSeries.values()),\n };\n },\n };\n\n return {\n manifest: manifestRadar,\n\n onInit(c: PluginContext) {\n ctx = c;\n // Setup the chart for Radar (centered origin, fixed bounds)\n ctx.chart.updateXAxis({ visible: false, min: -1.2, max: 1.2 });\n ctx.chart.updateYAxis('default', { visible: false, min: -1.2, max: 1.2 });\n },\n\n onRenderOverlay(pCtx: PluginContext, _event: AfterRenderEvent) {\n if (pCtx.chart.getActiveRenderer() === \"svg\") return;\n drawRadar(pCtx);\n },\n\n api\n };\n}\n\nexport default PluginRadar;\n\nexport type { \n PluginRadarConfig, \n RadarAPI, \n RadarSeriesData, \n RadarPoint \n} from './types';\n"],"names":["manifestRadar","DEFAULT_CONFIG","PluginRadar","userConfig","config","ctx","radarSeries","drawRadar","pCtx","_a","_b","_c","_d","_e","_f","render","ctx2d","plotArea","centerX","centerY","maxRadiusPixels","numCategories","angleStep","level","radius","i","angle","px","py","labelRadius","lx","ly","series","points","style","pathPoints","cat","idx","point","p","c","_event","data","id","res","categories","value"],"mappings":"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"}
|