flexdesk 0.17.11 → 0.17.13
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/CHANGELOG.md +33 -0
- package/css/base.css +19 -0
- package/css/flexdesk.css +28 -2
- package/css/overrides.css +9 -2
- package/dist/charts.js +3 -3
- package/dist/{chunk-NIJEJAZ7.js → chunk-2PM6ZMNS.js} +2 -2
- package/dist/{chunk-F35XSQWA.js → chunk-IG74S3ZH.js} +2 -2
- package/dist/{chunk-CVMCZZX2.js → chunk-MADMGRX2.js} +18 -7
- package/dist/chunk-MADMGRX2.js.map +7 -0
- package/dist/{chunk-2YTM3GJE.js → chunk-TLIV6QSU.js} +16 -5
- package/dist/{chunk-2YTM3GJE.js.map → chunk-TLIV6QSU.js.map} +2 -2
- package/dist/{chunk-BE2PU3LL.js → chunk-ZMH3OC7H.js} +2 -2
- package/dist/flexdesk.css +28 -2
- package/dist/flow.js +3 -3
- package/dist/tiles.js +5 -5
- package/dist/widgets.js +4 -4
- package/dist/wm.js +3 -3
- package/docs/components/charts.md +37 -1
- package/docs/components/menus.md +59 -0
- package/package.json +1 -1
- package/src/charts/plot_grid.js +21 -3
- package/src/charts/plot_popout_window.js +7 -0
- package/src/ui/components/managed_window.js +24 -6
- package/dist/chunk-CVMCZZX2.js.map +0 -7
- /package/dist/{chunk-NIJEJAZ7.js.map → chunk-2PM6ZMNS.js.map} +0 -0
- /package/dist/{chunk-F35XSQWA.js.map → chunk-IG74S3ZH.js.map} +0 -0
- /package/dist/{chunk-BE2PU3LL.js.map → chunk-ZMH3OC7H.js.map} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/charts/plotly_wrapper.js", "../src/charts/chart_types.js", "../src/charts/downsample.js", "../src/charts/plot_config.js", "../src/charts/series_transforms.js", "../src/charts/plot_grid.js", "../src/charts/plot_popout_window.js"],
|
|
4
|
-
"sourcesContent": ["/**\n * Plotly.js Wrapper\n *\n * Provides lazy loading of Plotly.js and helper functions for chart operations.\n * Supports streaming updates via Plotly.extendTraces() and Plotly.react().\n */\n\nimport { createRafResizeObserver } from '../ui/utils/raf_resize_observer.js';\n\n// Where Plotly lives is the CONSUMER's business, not the library's.\n//\n// This was `const PLOTLY_LOCAL = 'vendor/plotly/plotly-2.35.2.min.js'` \u2014 a\n// relative path into one particular application's directory tree. It happens to\n// work for EcoAgent and would 404 for anyone else, and the failure would arrive\n// as an empty chart with a console error, at runtime, only on the screens that\n// plot something.\n//\n// Plotly stays a PEER dependency: 4.4 MB that @flexdesk/charts refuses to bundle.\n//\n// There is NO DEFAULT. Leaving one in place would only have meant leaving\n// EcoAgent's exact versioned filename in the library \u2014 the same bug wearing a\n// setter \u2014 and it would fail for everyone else as an empty chart and a console\n// error, at runtime, on the screens that plot something.\n//\n// ensurePlotly() short-circuits when `window.Plotly` is already defined, which is\n// how EcoAgent works: it preloads Plotly with a <script> tag in index.html and\n// never reaches the loader below. A consumer that does not preload calls\n// setPlotlySource() instead. A consumer that does neither now gets told so.\nlet _plotlySrc = null;\n\n/** Point the loader at your copy of Plotly. Call before the first chart renders. */\nexport function setPlotlySource(src) {\n if (typeof src === 'string' && src) _plotlySrc = src;\n}\n\n// Loading promise for singleton pattern\nlet _plotlyLoadPromise = null;\n\n// Workarounds for Plotly.js 2.35.x running in Chromium-based pywebview.\nlet _plotlyPatchesInstalled = false;\nfunction _installPlotlyPatches() {\n if (_plotlyPatchesInstalled) return;\n _plotlyPatchesInstalled = true;\n\n // Plotly's internal mousemove handler assigns event.target which is\n // read-only in modern browsers. Replace the native getter with a\n // getter/setter pair so the assignment succeeds silently.\n const targetDesc = Object.getOwnPropertyDescriptor(Event.prototype, 'target');\n if (targetDesc && targetDesc.get && !targetDesc.set) {\n const origGetter = targetDesc.get;\n Object.defineProperty(Event.prototype, 'target', {\n configurable: true,\n enumerable: true,\n get() {\n return this._plotlyTarget ?? origGetter.call(this);\n },\n set(v) {\n this._plotlyTarget = v;\n }\n });\n }\n\n // Plotly calls getImageData() repeatedly on 2D canvases without the\n // willReadFrequently hint, triggering a Chromium performance warning.\n // Patch getContext to inject the hint for all 2D contexts.\n const _origGetContext = HTMLCanvasElement.prototype.getContext;\n HTMLCanvasElement.prototype.getContext = function (type, attrs) {\n if (type === '2d') {\n attrs = Object.assign({ willReadFrequently: true }, attrs);\n }\n return _origGetContext.call(this, type, attrs);\n };\n}\n\n// Run immediately on module import so the patches are active before any Plotly\n// chart is created (including during workspace hydration) \u2014 but ONLY in a DOM.\n//\n// Unguarded, this monkey-patched HTMLCanvasElement.prototype at module scope, so\n// `import '@flexdesk/charts'` threw `ReferenceError: HTMLCanvasElement is not defined`\n// the instant anything imported it outside a browser. That is the third module in\n// this library caught doing DOM work on import (see inline_renamer.js and\n// tooltip_service.js), and all three were found by the same test: one that does\n// nothing but import each entry point. A library whose entry point cannot be\n// imported without a DOM cannot be unit-tested, server-rendered, or loaded in a\n// worker.\nif (typeof HTMLCanvasElement !== 'undefined') {\n _installPlotlyPatches();\n}\n\n/**\n * Dark theme layout defaults matching the shell's dark UI\n */\nexport const DARK_THEME_LAYOUT = {\n paper_bgcolor: 'transparent',\n plot_bgcolor: 'transparent',\n font: {\n family: 'Inter, -apple-system, BlinkMacSystemFont, sans-serif',\n size: 11,\n color: '#cccccc'\n },\n margin: { l: 50, r: 20, t: 30, b: 40 },\n legend: {\n bgcolor: 'rgba(0,0,0,0)',\n font: { color: '#cccccc' }\n },\n xaxis: {\n gridcolor: '#333333',\n linecolor: '#444444',\n tickcolor: '#666666',\n zerolinecolor: '#444444'\n },\n yaxis: {\n gridcolor: '#333333',\n linecolor: '#444444',\n tickcolor: '#666666',\n zerolinecolor: '#444444'\n },\n // Hover tooltip styling for dark theme\n hoverlabel: {\n bgcolor: '#1e2228',\n bordercolor: '#444444',\n font: {\n family: 'Inter, -apple-system, BlinkMacSystemFont, sans-serif',\n size: 12,\n color: '#e0e0e0'\n }\n },\n // 3D scene defaults\n scene: {\n xaxis: {\n gridcolor: '#333333',\n linecolor: '#444444',\n backgroundcolor: 'rgba(0,0,0,0)'\n },\n yaxis: {\n gridcolor: '#333333',\n linecolor: '#444444',\n backgroundcolor: 'rgba(0,0,0,0)'\n },\n zaxis: {\n gridcolor: '#333333',\n linecolor: '#444444',\n backgroundcolor: 'rgba(0,0,0,0)'\n },\n bgcolor: 'rgba(0,0,0,0)'\n }\n};\n\n/** The PNG export's file name (without extension) when the embedder names none. */\nexport const DEFAULT_CHART_EXPORT_FILENAME = 'chart';\n\n/**\n * Default Plotly config options\n */\nexport const DEFAULT_CONFIG = {\n responsive: true,\n displaylogo: false,\n displayModeBar: false, // Hide modebar completely\n scrollZoom: true, // Allow zoom with scroll wheel instead\n toImageButtonOptions: {\n format: 'png',\n filename: DEFAULT_CHART_EXPORT_FILENAME,\n scale: 2\n }\n};\n\n/**\n * Name the file a chart's PNG export saves as (Plotly adds `.png`). Applies to\n * every chart created afterwards through DEFAULT_CONFIG; a chart's own\n * `config.toImageButtonOptions` still wins.\n *\n * @param {string} [filename=DEFAULT_CHART_EXPORT_FILENAME]\n */\nexport function setChartExportFilename(filename = DEFAULT_CHART_EXPORT_FILENAME) {\n DEFAULT_CONFIG.toImageButtonOptions.filename =\n (typeof filename === 'string' && filename) ? filename : DEFAULT_CHART_EXPORT_FILENAME;\n}\n\n/** @returns {string} The PNG export's file name (without extension). */\nexport function getChartExportFilename() {\n return DEFAULT_CONFIG.toImageButtonOptions.filename;\n}\n\n/**\n * Load Plotly.js from CDN.\n * Uses singleton pattern to avoid multiple loads.\n * @returns {Promise<Plotly>} The Plotly library object\n */\nexport async function ensurePlotly() {\n // Already loaded\n if (typeof Plotly !== 'undefined') {\n return Plotly;\n }\n\n // Loading in progress\n if (_plotlyLoadPromise) {\n return _plotlyLoadPromise;\n }\n\n if (!_plotlySrc) {\n throw new Error(\n '[twm/charts] Plotly is not loaded and no source is configured. '\n + 'Either load Plotly yourself (a <script> tag that sets window.Plotly), '\n + 'or call setPlotlySource(\"/path/to/plotly.min.js\") before rendering a chart.');\n }\n\n // Start loading \u2014 make Plotly's UMD header take its browser-global branch\n // WITHOUT asking any other script on the page to give up AMD, even for a\n // moment.\n //\n // \u2550\u2550 WHY THE SCRIPT TAG IS NOT USED FIRST \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n //\n // Plotly's header asks one question \u2014 `typeof define === 'function' &&\n // define.amd` \u2014 and takes the AMD branch if the answer is yes, leaving\n // `window.Plotly` unset because nothing calls the anonymous module back. A\n // `<script>` tag therefore has to change what that question answers, and a\n // global is the only place to change it. That is what this function used to\n // do: it hid `define.amd` for the length of the fetch (see\n // `loadThroughMaskedDefine` below for the two ways a cruder version of that\n // breaks).\n //\n // MASKING IS STILL WRONG, AND MONACO IS THE PROOF. The window lasts as long\n // as a 4.4 MB download, and any OTHER script that executes inside it asks\n // the same question and gets the answer meant for Plotly. Monaco's\n // `editor.main.js` \u2014 3.7 MB, fetched on demand, so it lands wherever it\n // lands \u2014 asks it twice:\n //\n // typeof define==\"function\"&&define.amd ? define(ne[447], \u2026) // marked\n // \u2026 || typeof define==\"function\"&&define.amd) && (globalThis.monaco = m)\n //\n // The first is the copy of `marked` bundled INSIDE `editor.main.js`. Told\n // there is no AMD, it registers itself as `globalThis.marked` instead of as\n // the module `vs/base/common/marked/marked` \u2014 so Monaco's loader goes\n // looking for that module as a FILE, which the `min` distribution does not\n // ship (it is bundled, precisely here). The 404 fails the whole\n // `vs/editor/editor.main` require:\n //\n // Loading \"vs/base/common/marked/marked\" failed\n // Here are the modules that depend on it: vs/base/browser/markdownRenderer\n //\n // The second means `window.monaco` is never set even if the first is\n // survived. Monaco's `monacoReady` has no reject path, so neither shows up\n // as a failure: the editor simply never arrives, for the life of the page,\n // and every consumer sits in its textarea fallback. Measured on the running\n // deployment on 2026-09-04: 5 boots in 8 lost Monaco this way, 0 in 8 with\n // the Plotly warm-up removed.\n //\n // \u2550\u2550 SO THE GLOBALS ARE NOT TOUCHED AT ALL \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n //\n // Fetch the source, then evaluate it in a function whose PARAMETERS are\n // named `define`, `module` and `exports`. Inside that scope `typeof define`\n // is \"undefined\" \u2014 the answer Plotly needs \u2014 while `window.define` is never\n // read, written or deleted, so no other script can observe anything. The\n // window is not a window at all: it is one synchronous evaluation, and\n // nothing else can run inside it by construction.\n //\n // The masked-tag path stays as the FALLBACK for a source this page cannot\n // fetch \u2014 a CDN without CORS is the case that matters, and it is exactly the\n // case where a `<script>` tag still works.\n _plotlyLoadPromise = (async () => {\n let code;\n try {\n const response = await fetch(_plotlySrc, { credentials: 'same-origin' });\n if (!response.ok) throw new Error(`HTTP ${response.status}`);\n code = await response.text();\n } catch (err) {\n // The FETCH failed, which a tag may still survive. An evaluation\n // failure is not caught here: it would fail identically through a\n // tag, and swallowing it would replace a real message with a\n // misleading one.\n return loadThroughMaskedDefine();\n }\n return evaluateWithoutAmd(code, _plotlySrc);\n })();\n\n return _plotlyLoadPromise;\n}\n\n/**\n * Run Plotly's bundle with the three UMD globals shadowed as local names.\n *\n * `new Function` is not strict, so `this` is the global object inside the body \u2014\n * which is what Plotly's header is invoked with (`}(self, \u2026)` in 2.x, `this` in\n * older builds), and is why the browser-global branch still lands `Plotly` on\n * the window rather than on a scope that disappears.\n *\n * @param {string} code the bundle's source\n * @param {string} src where it came from, for the debugger's file list\n * @returns {object} the `Plotly` global\n */\nfunction evaluateWithoutAmd(code, src) {\n // eslint-disable-next-line no-new-func\n const run = new Function('define', 'module', 'exports',\n `${code}\\n//# sourceURL=${src}`);\n run(undefined, undefined, undefined);\n if (typeof Plotly === 'undefined') {\n throw new Error(`Plotly.js was evaluated from ${src} but did not define a `\n + 'Plotly global \u2014 the file may not be a Plotly UMD bundle.');\n }\n return Plotly;\n}\n\n/**\n * The `<script>` tag path, for a source this page cannot fetch.\n *\n * \u2550\u2550 WHY `define` IS MASKED AND NOT REMOVED \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n *\n * Hiding `window.define` outright breaks the page two ways, both observed on a\n * running deployment on 2026-08-31:\n *\n * 1. `window.define = undefined`, restored on load. Monaco's `loader.js`\n * installs an AMD loader DURING the window, Plotly's header then sees\n * `typeof define === 'function' && define.amd`, registers as an anonymous\n * module nothing calls back, and the load \"succeeds\" with `window.Plotly`\n * still undefined:\n * This chart could not be drawn: Plotly.js loaded but Plotly global\n * not found\n * \u2014 true, unhelpful, and it sends the reader hunting for a missing file\n * that is being served correctly.\n *\n * 2. The mirror. Monaco loads in TWO stages: `loader.js` sets `define`, and\n * `editor.main.js` arrives later and calls it. If stage two lands while\n * `define` is hidden:\n * editor.main.js:5 Uncaught TypeError: globalDefine is not a function\n * One race costs the chart; the other costs the editor.\n *\n * Masking the PROPERTY rather than the function fixes both \u2014 `define` stays\n * callable, `amd` is withheld \u2014 and it is still not safe for anybody else who\n * asks the `define.amd` question inside the window. `ensurePlotly` says what\n * that costs; this path is taken only when there is no alternative.\n *\n * @returns {Promise<object>} the `Plotly` global\n */\nfunction loadThroughMaskedDefine() {\n return new Promise((resolve, reject) => {\n const hadDefine = 'define' in window;\n const savedDefine = window.define;\n let arrivedDefine; // what somebody installed mid-window\n let arrived = false;\n let guarded = false;\n\n /** The same function with `amd` withheld. Plotly reads `define.amd` and\n * stops; everyone else calls it and it behaves. */\n const maskAmd = (value) => {\n if (typeof value !== 'function') return undefined;\n const masked = function define(...args) { return value.apply(this, args); };\n for (const key of Object.getOwnPropertyNames(value)) {\n if (key === 'amd' || key === 'length' || key === 'name') continue;\n try { masked[key] = value[key]; } catch { /* getters that throw */ }\n }\n masked.amd = undefined;\n return masked;\n };\n\n try {\n Object.defineProperty(window, 'define', {\n configurable: true,\n enumerable: true,\n get: () => maskAmd(arrived ? arrivedDefine : savedDefine),\n set: (value) => { arrivedDefine = value; arrived = true; },\n });\n guarded = true;\n } catch {\n // A host that refuses the redefinition still gets the old\n // behaviour, which is right far more often than it is wrong.\n window.define = undefined;\n }\n\n /** Put the REAL `define` back, exactly once, preferring what arrived. */\n const release = () => {\n const value = arrived ? arrivedDefine : savedDefine;\n if (guarded) {\n delete window.define;\n guarded = false;\n }\n // `hadDefine` matters: assigning `undefined` leaves an own property\n // whose value is undefined, and `'define' in window` then answers\n // true for a global that was never there. Some loaders test that.\n if (arrived || hadDefine) window.define = value;\n };\n\n const script = document.createElement('script');\n script.src = _plotlySrc;\n script.async = true;\n\n script.onload = () => {\n release();\n if (typeof Plotly !== 'undefined') {\n resolve(Plotly);\n } else {\n reject(new Error('Plotly.js loaded but Plotly global not found. '\n + 'Something defined an AMD loader while it was loading, so '\n + 'Plotly registered as a module instead of a global.'));\n }\n };\n\n script.onerror = () => {\n release();\n reject(new Error(`Failed to load Plotly.js from ${_plotlySrc} \u2014 `\n + 'call setPlotlySource() with the path to your copy.'));\n };\n\n document.head.appendChild(script);\n });\n}\n\n/**\n * Create a new Plotly chart.\n * @param {HTMLElement} container - Container element for the chart\n * @param {Array} data - Array of trace objects\n * @param {Object} layout - Layout configuration\n * @param {Object} config - Plotly config options\n * @returns {Promise<HTMLElement>} The chart element\n */\nexport async function createChart(container, data, layout = {}, config = {}) {\n const Plotly = await ensurePlotly();\n\n const mergedLayout = {\n ...DARK_THEME_LAYOUT,\n ...layout\n };\n\n const mergedConfig = {\n ...DEFAULT_CONFIG,\n ...config\n };\n\n return Plotly.newPlot(container, data, mergedLayout, mergedConfig);\n}\n\n/**\n * Update chart data and layout efficiently.\n * Uses Plotly.react() which is optimized for updates.\n * @param {HTMLElement} container - Chart container\n * @param {Array} data - New trace data\n * @param {Object} layout - Layout updates\n */\nexport async function updateChart(container, data, layout = {}) {\n const Plotly = await ensurePlotly();\n\n const mergedLayout = {\n ...DARK_THEME_LAYOUT,\n ...layout\n };\n\n return Plotly.react(container, data, mergedLayout);\n}\n\n/**\n * Extend traces with new data points (for streaming).\n * More efficient than full update for appending data.\n * @param {HTMLElement} container - Chart container\n * @param {Object} update - Data to extend: { x: [[...]], y: [[...]] }\n * @param {Array<number>} traceIndices - Which traces to extend\n * @param {number} maxPoints - Maximum points to keep (optional)\n */\nexport async function extendTraces(container, update, traceIndices, maxPoints = null) {\n const Plotly = await ensurePlotly();\n\n if (maxPoints) {\n return Plotly.extendTraces(container, update, traceIndices, maxPoints);\n }\n return Plotly.extendTraces(container, update, traceIndices);\n}\n\n/**\n * Relayout chart (update layout only, no data change).\n * @param {HTMLElement} container - Chart container\n * @param {Object} layoutUpdate - Layout properties to update\n */\nexport async function relayout(container, layoutUpdate) {\n const Plotly = await ensurePlotly();\n return Plotly.relayout(container, layoutUpdate);\n}\n\n/**\n * Restyle traces (update trace properties without full redraw).\n * @param {HTMLElement} container - Chart container\n * @param {Object} styleUpdate - Style properties to update\n * @param {Array<number>} traceIndices - Which traces to update\n */\nexport async function restyle(container, styleUpdate, traceIndices) {\n const Plotly = await ensurePlotly();\n return Plotly.restyle(container, styleUpdate, traceIndices);\n}\n\n/**\n * Delete all traces and release resources.\n * @param {HTMLElement} container - Chart container\n */\nexport async function purge(container) {\n const Plotly = await ensurePlotly();\n return Plotly.purge(container);\n}\n\n/**\n * Check if container has a Plotly chart.\n * @param {HTMLElement} container - Container element\n * @returns {boolean}\n */\nexport function hasPlot(container) {\n return container && container._fullLayout !== undefined;\n}\n\n/**\n * Resize chart to fit container.\n * Call this when container size changes.\n * @param {HTMLElement} container - Chart container\n */\nexport async function resize(container) {\n const Plotly = await ensurePlotly();\n return Plotly.Plots.resize(container);\n}\n\n/**\n * Convert hex color to rgba.\n * @param {string} hex - Hex color code\n * @param {number} alpha - Alpha value (0-1)\n * @returns {string} rgba color string\n */\nexport function hexToRgba(hex, alpha = 1) {\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n if (!result) return hex;\n const r = parseInt(result[1], 16);\n const g = parseInt(result[2], 16);\n const b = parseInt(result[3], 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n\n// Solarized theme colors matching legacy plot_node.js\nexport const COLOR_PALETTE = [\n '#268bd2', // Solarized Blue\n '#d33682', // Solarized Magenta\n '#cb4b16', // Solarized Orange\n '#2aa198', // Solarized Cyan\n '#6a5acd', // SlateBlue/Purple\n '#7a7d80', // Gray\n '#9fb6cf', // Gray-Blue\n];\n\n/**\n * Get color from palette by index.\n * @param {number} index - Series index\n * @returns {string} Color hex code\n */\nexport function getSeriesColor(index) {\n return COLOR_PALETTE[index % COLOR_PALETTE.length];\n}\n\n/**\n * Create a Plotly chart with deferred rendering support.\n * Handles zero-dimension containers by waiting for valid dimensions via ResizeObserver.\n * @param {HTMLElement} container - Container element for the chart\n * @param {Array} traces - Array of trace objects\n * @param {Object} layout - Layout configuration\n * @param {Object} config - Plotly config options\n * @returns {Promise<{element: HTMLElement, cleanup: Function}>} Chart element and cleanup function\n */\nexport async function createChartDeferred(container, traces, layout = {}, config = {}) {\n const Plotly = await ensurePlotly();\n\n const mergedLayout = {\n ...DARK_THEME_LAYOUT,\n ...layout\n };\n\n const mergedConfig = {\n ...DEFAULT_CONFIG,\n ...config\n };\n\n const w = container.offsetWidth;\n const h = container.offsetHeight;\n\n // Cleanup function to return\n let resizeObserver = null;\n const cleanup = () => {\n if (resizeObserver) {\n resizeObserver.disconnect();\n resizeObserver = null;\n }\n };\n\n // If dimensions are valid, render immediately\n if (w > 0 && h > 0) {\n await Plotly.newPlot(container, traces, mergedLayout, mergedConfig);\n // Still set up resize observer for ongoing resizes\n resizeObserver = createRafResizeObserver(() => {\n if (hasPlot(container)) {\n Plotly.Plots.resize(container).catch(() => {});\n }\n });\n resizeObserver.observe(container);\n return { element: container, cleanup };\n }\n\n // Dimensions are zero - wait for valid dimensions via ResizeObserver\n return new Promise((resolve) => {\n let rendered = false;\n resizeObserver = createRafResizeObserver((entries) => {\n for (const entry of entries) {\n const { width, height } = entry.contentRect;\n if (width > 0 && height > 0) {\n if (!rendered) {\n rendered = true;\n Plotly.newPlot(container, traces, mergedLayout, mergedConfig).then(() => {\n resolve({ element: container, cleanup });\n }).catch(() => {\n resolve({ element: container, cleanup });\n });\n } else if (hasPlot(container)) {\n // Handle subsequent resizes\n Plotly.Plots.resize(container).catch(() => {});\n }\n }\n }\n });\n resizeObserver.observe(container);\n });\n}\n", "/**\n * Chart Types and Trace Configurations\n *\n * Defines trace configurations for Plotly.js and provides mapping\n * from Chart.js options to Plotly equivalents.\n */\n\nimport { getSeriesColor, hexToRgba } from './plotly_wrapper.js';\n\n/**\n * Available 2D chart types\n */\nexport const CHART_TYPES_2D = Object.freeze([\n { value: 'line', label: 'Line' },\n { value: 'bar', label: 'Bar' },\n { value: 'scatter', label: 'Scatter' },\n { value: 'area', label: 'Area' },\n { value: 'area-stacked', label: 'Area (Stacked %)' },\n { value: 'phase', label: 'Phase' },\n // Categorical part-of-whole. They belong in this list because the list is\n // what a consumer renders as its chart-type dropdown \u2014 but they are NOT\n // (x[], y[]) charts, and `buildTrace` leaves for them before the switch:\n // read the early return there before adding a fourth. `indicator` is\n // deliberately NOT here, because it takes a SCALAR \u2014 a dropdown offering it\n // beside these would offer a rendering of data the chart is not bound to.\n { value: 'pie', label: 'Pie' },\n { value: 'donut', label: 'Donut' },\n { value: 'funnel', label: 'Funnel' },\n]);\n\n/**\n * Available 3D chart types\n */\nexport const CHART_TYPES_3D = Object.freeze([\n { value: 'scatter3d', label: '3D Scatter' },\n { value: 'line3d', label: '3D Line' },\n { value: 'surface', label: '3D Surface' },\n]);\n\n/**\n * All chart types combined\n */\nexport const ALL_CHART_TYPES = Object.freeze([...CHART_TYPES_2D, ...CHART_TYPES_3D]);\n\n/**\n * Check if chart type is 3D\n * @param {string} chartType\n * @returns {boolean}\n */\nexport function is3DChart(chartType) {\n return ['scatter3d', 'line3d', 'surface'].includes(chartType);\n}\n\n/**\n * Line style mapping (Chart.js borderDash to Plotly dash)\n */\nconst LINE_DASH_MAP = {\n solid: 'solid',\n dashed: 'dash',\n dotted: 'dot',\n};\n\n/**\n * Interpolation mapping (Chart.js to Plotly line shape). 'auto' draws straight\n * segments between the points, as 'linear' does.\n */\nconst INTERPOLATION_MAP = {\n linear: 'linear',\n step: 'hv', // horizontal-vertical step\n cubic: 'spline', // smooth spline\n auto: 'linear',\n};\n\n/**\n * Build a Plotly trace from series configuration.\n * @param {Object} options\n * @param {string} options.chartType - Chart type (line, bar, scatter, area, scatter3d, etc.)\n * @param {Array} options.x - X-axis data\n * @param {Array} options.y - Y-axis data\n * @param {Array} [options.z] - Z-axis data (for 3D charts)\n * @param {string} options.name - Series name/label\n * @param {string} [options.color] - Series color (hex)\n * @param {number} [options.lineWidth] - Line width in pixels\n * @param {string} [options.lineStyle] - Line style: solid, dashed, dotted\n * @param {string} [options.interpolation] - Interpolation: linear, step, cubic, or auto (drawn as linear)\n * @param {string} [options.yAxisId] - Y-axis identifier (y, y2, y3, etc.)\n * @param {boolean} [options.showMarkers] - Show data point markers\n * @param {number} [options.seriesIndex] - Index for default color selection\n * @param {Array<string>} [options.colors] - Per-CATEGORY colors, pie/donut/funnel only\n * @returns {Object} Plotly trace object\n */\nexport function buildTrace(options) {\n const {\n chartType = 'line',\n x = [],\n y = [],\n z = null,\n name = 'Series',\n color = null,\n lineWidth = 2,\n lineStyle = 'solid',\n interpolation = 'linear',\n yAxisId = 'y',\n showMarkers = false,\n seriesIndex = 0,\n stackGroup = null,\n colors = null,\n } = options;\n\n const seriesColor = color || getSeriesColor(seriesIndex);\n\n // \u2500\u2500 categorical part-of-whole: pie, donut, funnel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // These leave here, ABOVE the switch, and that placement is the whole\n // point rather than a tidiness. Everything below is written against the\n // base trace built at the end of the switch \u2014 `{type, name, x, y}` \u2014 and a\n // pie has neither an x nor a y: Plotly reads `labels` and `values`, and a\n // stray `x` rides along ignored right up until someone puts the trace on a\n // shared axis and it is not ignored any more.\n //\n // The marker block further down is the sharper edge. It fires on\n // `showMarkers` for ANY chart type and assigns `marker = {color, size}` \u2014\n // which would overwrite `marker.colors`, the per-slice palette, with one\n // scalar colour and turn a seven-slice pie into a single blue disc. A\n // `case` in the switch cannot avoid either hazard; leaving before both can.\n if (chartType === 'pie' || chartType === 'donut' || chartType === 'funnel') {\n // `seriesIndex` is not consulted: a pie IS the chart, so its slices\n // start at the top of the palette rather than continuing someone\n // else's series numbering.\n const sliceColors = Array.isArray(colors) && colors.length\n ? colors\n : y.map((_, i) => getSeriesColor(i));\n\n if (chartType === 'funnel') {\n // A funnel is bar-shaped, so it is `marker.color` (singular, and\n // an array is legal) \u2014 NOT the `marker.colors` a pie wants. The\n // two spellings are not interchangeable and neither errors.\n return {\n type: 'funnel',\n name,\n y: x, // stages read down the categorical axis\n x: y, // ...and the measure runs across\n marker: { color: sliceColors },\n textinfo: 'value+percent initial',\n };\n }\n\n return {\n type: 'pie',\n name,\n labels: x,\n values: y,\n marker: { colors: sliceColors },\n // Plotly sorts slices descending by default. The caller has\n // already ordered its rows \u2014 a dashboard binding carries its own\n // `sort` \u2014 and a second, invisible reordering here makes the chart\n // disagree with the table beside it and with the config that\n // produced both.\n sort: false,\n ...(chartType === 'donut' ? { hole: 0.55 } : {}),\n };\n }\n\n // Determine Plotly trace type and mode\n let plotlyType, mode;\n switch (chartType) {\n case 'line':\n plotlyType = 'scatter';\n mode = showMarkers ? 'lines+markers' : 'lines';\n break;\n case 'scatter':\n plotlyType = 'scatter';\n mode = 'markers';\n break;\n case 'area':\n case 'area-stacked':\n plotlyType = 'scatter';\n mode = showMarkers ? 'lines+markers' : 'lines';\n break;\n case 'phase':\n plotlyType = 'scatter';\n mode = 'lines+markers';\n break;\n case 'bar':\n plotlyType = 'bar';\n mode = undefined;\n break;\n case 'scatter3d':\n plotlyType = 'scatter3d';\n mode = 'markers';\n break;\n case 'line3d':\n plotlyType = 'scatter3d';\n mode = showMarkers ? 'lines+markers' : 'lines';\n break;\n case 'surface':\n plotlyType = 'surface';\n mode = undefined;\n break;\n default:\n plotlyType = 'scatter';\n mode = showMarkers ? 'lines+markers' : 'lines';\n }\n\n // Build base trace\n const trace = {\n type: plotlyType,\n name,\n x,\n y,\n };\n\n // Add mode if applicable\n if (mode) {\n trace.mode = mode;\n }\n\n // Add z-axis data for 3D charts\n if (z && is3DChart(chartType)) {\n // Surface charts require z to be a 2D array\n // If z is 1D (time series data), use mesh3d with Delaunay triangulation\n if (chartType === 'surface') {\n const zIs2D = Array.isArray(z) && z.length > 0 && Array.isArray(z[0]);\n if (zIs2D) {\n trace.z = z;\n } else {\n // Use mesh3d with Delaunay triangulation for 1D scattered points\n console.info('[chart_types] Surface chart with 1D z data - using mesh3d with Delaunay triangulation');\n trace.type = 'mesh3d';\n trace.x = x;\n trace.y = y;\n trace.z = z;\n trace.alphahull = 0; // Delaunay triangulation (convex hull = -1, 0 = Delaunay)\n trace.opacity = 0.8;\n trace.color = seriesColor;\n trace.flatshading = true;\n trace.lighting = {\n ambient: 0.6,\n diffuse: 0.5,\n specular: 0.2,\n };\n // Skip surface-specific config below\n return trace;\n }\n } else {\n trace.z = z;\n }\n }\n\n // Phase chart: line with small markers\n if (chartType === 'phase') {\n trace.line = {\n color: seriesColor,\n width: lineWidth,\n dash: LINE_DASH_MAP[lineStyle] || 'solid',\n };\n trace.marker = {\n color: seriesColor,\n size: 3,\n };\n return trace;\n }\n\n // Line configuration (for line/area charts)\n if (['line', 'area', 'area-stacked', 'line3d'].includes(chartType)) {\n trace.line = {\n color: seriesColor,\n width: lineWidth,\n dash: LINE_DASH_MAP[lineStyle] || 'solid',\n shape: INTERPOLATION_MAP[interpolation] || 'linear',\n };\n }\n\n // Marker configuration\n if (['scatter', 'scatter3d'].includes(chartType) || showMarkers) {\n trace.marker = {\n color: seriesColor,\n size: chartType === 'scatter3d' ? 4 : 6,\n };\n }\n\n // Normalized stacked area: each Y-axis is its own stack group, each summing to 1.\n if (chartType === 'area-stacked') {\n trace.stackgroup = yAxisId;\n trace.groupnorm = 'fraction';\n trace.fillcolor = hexToRgba(seriesColor, 0.5);\n trace.line = { ...(trace.line || {}), width: 0.5, color: seriesColor };\n trace.mode = 'lines';\n }\n // Fill for area charts (non-stacked)\n else if (chartType === 'area' && !stackGroup) {\n trace.fill = 'tozeroy';\n trace.fillcolor = hexToRgba(seriesColor, 0.3);\n }\n // Stacked area via explicit stackGroup on any chart type\n else if (stackGroup) {\n trace.stackgroup = stackGroup;\n trace.fillcolor = hexToRgba(seriesColor, 0.5);\n trace.line = { ...(trace.line || {}), width: 0.5, color: seriesColor };\n trace.mode = 'lines';\n }\n\n // Bar color\n if (chartType === 'bar') {\n trace.marker = {\n color: seriesColor,\n };\n }\n\n // Surface colorscale\n if (chartType === 'surface') {\n trace.colorscale = 'Viridis';\n trace.showscale = true;\n }\n\n // Y-axis assignment (for multi-axis support)\n if (!is3DChart(chartType) && yAxisId && yAxisId !== 'y') {\n trace.yaxis = yAxisId;\n }\n\n return trace;\n}\n\n/**\n * Build layout for Y-axis based on configuration.\n * @param {Object} options\n * @param {string} options.axisId - Axis identifier (y, y2, y3, etc.)\n * @param {string} [options.title] - Axis title\n * @param {string} [options.position] - Axis position: left or right\n * @param {string} [options.scaleType] - Scale type: linear or log\n * @param {number} [options.min] - Minimum value\n * @param {number} [options.max] - Maximum value\n * @param {number} [options.step] - Tick step size\n * @param {boolean} [options.showGrid] - Show grid lines\n * @param {number|null} [options.axisPosition] - Explicit position in normalized coords (0-1), null for default\n * @returns {Object} Plotly axis layout object\n */\nexport function buildYAxisLayout(options) {\n const {\n axisId = 'yaxis',\n title = '',\n position = 'left',\n scaleType = 'linear',\n min = null,\n max = null,\n step = null,\n showGrid = true,\n axisPosition = null,\n } = options;\n\n const layout = {\n title: { text: title },\n type: scaleType === 'log' ? 'log' : 'linear',\n side: position,\n gridcolor: 'rgba(255,255,255,0.05)',\n linecolor: 'rgba(255,255,255,0.08)',\n tickcolor: 'rgba(255,255,255,0.3)',\n zerolinecolor: 'rgba(255,255,255,0.06)',\n showgrid: showGrid,\n automargin: true, // Auto-expand margin for tick labels\n };\n\n // Set range if min/max provided.\n // Both bounds: fixed range (autorange off).\n // One-sided: use autorangeoptions so Plotly auto-ranges within data but respects the cap/floor.\n // Plotly does not accept null in a range array \u2014 [null, max] silently sets the lower bound to 0.\n if (min !== null && max !== null) {\n layout.autorange = false;\n layout.range = [min, max];\n } else if (min !== null || max !== null) {\n layout.autorange = true;\n layout.autorangeoptions = {};\n if (min !== null) layout.autorangeoptions.minallowed = min;\n if (max !== null) layout.autorangeoptions.maxallowed = max;\n }\n\n // Set tick step if provided\n if (step !== null && step > 0) {\n layout.dtick = step;\n }\n\n // For secondary axes, overlay on the first y-axis\n if (axisId !== 'yaxis') {\n layout.overlaying = 'y';\n layout.anchor = 'free';\n\n // Use explicit position if provided (for proper multi-axis layout)\n // axisPosition is in normalized figure coordinates (0-1)\n if (axisPosition !== null) {\n layout.position = axisPosition;\n } else {\n // Fallback: position at domain edge (0 for left, 1 for right)\n layout.position = position === 'left' ? 0 : 1;\n }\n }\n\n return layout;\n}\n\n/**\n * Build X-axis layout.\n * @param {Object} options\n * @param {string} [options.title] - Axis title\n * @param {string} [options.scaleType] - Scale type: linear or log\n * @param {number} [options.min] - Minimum value\n * @param {number} [options.max] - Maximum value\n * @returns {Object} Plotly xaxis layout object\n */\nexport function buildXAxisLayout(options) {\n const {\n title = 'Time',\n scaleType = 'linear',\n min = null,\n max = null,\n } = options;\n\n const layout = {\n title: { text: title },\n type: scaleType === 'log' ? 'log' : 'linear',\n gridcolor: 'rgba(255,255,255,0.05)',\n linecolor: 'rgba(255,255,255,0.08)',\n tickcolor: 'rgba(255,255,255,0.3)',\n zerolinecolor: 'rgba(255,255,255,0.06)',\n automargin: true,\n };\n\n if (min !== null || max !== null) {\n layout.range = [min, max];\n }\n\n return layout;\n}\n\n/**\n * Build 3D scene layout.\n * @param {Object} options\n * @param {string} [options.xTitle] - X-axis title\n * @param {string} [options.yTitle] - Y-axis title\n * @param {string} [options.zTitle] - Z-axis title\n * @param {string} [options.zScale] - Z-axis scale type: 'linear' or 'log'\n * @param {number} [options.zMin] - Z-axis minimum value\n * @param {number} [options.zMax] - Z-axis maximum value\n * @param {number} [options.zStep] - Z-axis tick step size\n * @returns {Object} Plotly scene layout object\n */\nexport function build3DSceneLayout(options) {\n const {\n xTitle = 'X',\n yTitle = 'Y',\n zTitle = 'Z',\n zScale = 'linear',\n zMin = null,\n zMax = null,\n zStep = null,\n } = options;\n\n const zaxis = {\n title: { text: zTitle },\n type: zScale === 'log' ? 'log' : 'linear',\n gridcolor: 'rgba(255,255,255,0.05)',\n linecolor: 'rgba(255,255,255,0.08)',\n backgroundcolor: 'rgba(0,0,0,0)',\n };\n\n // Set range if min/max provided\n if (zMin !== null || zMax !== null) {\n zaxis.range = [zMin, zMax];\n }\n\n // Set tick step if provided\n if (zStep !== null && zStep > 0) {\n zaxis.dtick = zStep;\n }\n\n return {\n xaxis: {\n title: { text: xTitle },\n gridcolor: 'rgba(255,255,255,0.05)',\n linecolor: 'rgba(255,255,255,0.08)',\n backgroundcolor: 'rgba(0,0,0,0)',\n },\n yaxis: {\n title: { text: yTitle },\n gridcolor: 'rgba(255,255,255,0.05)',\n linecolor: 'rgba(255,255,255,0.08)',\n backgroundcolor: 'rgba(0,0,0,0)',\n },\n zaxis,\n bgcolor: 'rgba(0,0,0,0)',\n };\n}\n\n/**\n * Build legend layout.\n * @param {string} position - Legend position: top, bottom, left, right, hidden\n * @returns {Object} Plotly legend layout\n */\nexport function buildLegendLayout(position) {\n if (position === 'hidden') {\n return { showlegend: false };\n }\n\n const baseLayout = {\n showlegend: true,\n bgcolor: 'rgba(0,0,0,0)',\n font: { color: '#cccccc' },\n };\n\n switch (position) {\n case 'top':\n return {\n ...baseLayout,\n legend: {\n ...baseLayout,\n orientation: 'h',\n y: 1.1,\n yanchor: 'bottom',\n x: 0.5,\n xanchor: 'center',\n },\n };\n case 'bottom':\n return {\n ...baseLayout,\n legend: {\n ...baseLayout,\n orientation: 'h',\n y: -0.15,\n yanchor: 'top',\n x: 0.5,\n xanchor: 'center',\n },\n };\n case 'left':\n return {\n ...baseLayout,\n legend: {\n ...baseLayout,\n orientation: 'v',\n x: -0.15,\n xanchor: 'right',\n y: 0.5,\n yanchor: 'middle',\n },\n };\n case 'right':\n default:\n return {\n ...baseLayout,\n legend: {\n ...baseLayout,\n orientation: 'v',\n x: 1.02,\n xanchor: 'left',\n y: 0.5,\n yanchor: 'middle',\n },\n };\n }\n}\n\n/**\n * Build Plotly layout shapes + annotations for reference lines and shaded x-bands.\n *\n * @param {Object} opts\n * @param {Array<{yAxisId?:string, value:number, label?:string, color?:string, lineStyle?:string, lineWidth?:number, labelX?:number}>} [opts.referenceLines]\n * Horizontal threshold lines drawn across the plot, anchored to a specific Y axis.\n * `yAxisId` matches an axis id in sp.yAxes[].id; omitted \u2192 first axis.\n * @param {Array<{x0:number, x1:number, label?:string, color?:string, opacity?:number, labelY?:number, labelColor?:string}>} [opts.shadedBands]\n * Vertical stripes (rectangles spanning full y range) to mark policy/recession periods.\n * @param {Array<{x:(number|string|Date), label?:string, color?:string, lineStyle?:string, lineWidth?:number, labelY?:number}>} [opts.verticalLines]\n * Vertical markers at one x \u2014 a \"today\" line on a burndown. Drawn full height\n * (`yref: 'paper'`), after the reference lines, so a call without them builds\n * exactly what it built before they existed. `x` is in the x axis's own units:\n * a number, a category, or a date string/Date on a date axis.\n * @param {Object<string,string>} [opts.yRefByAxisId]\n * Mapping from subplot yAxes[i].id \u2192 Plotly yref ('y', 'y2', ...).\n * @returns {{shapes: Array, annotations: Array}}\n */\nexport function buildOverlayShapes(opts = {}) {\n const { referenceLines = [], shadedBands = [], verticalLines = [], yRefByAxisId = {} } = opts;\n const shapes = [];\n const annotations = [];\n const dashMap = { solid: 'solid', dashed: 'dash', dotted: 'dot', dashdot: 'dashdot' };\n\n for (const band of shadedBands) {\n if (band.x0 == null || band.x1 == null) continue;\n shapes.push({\n type: 'rect',\n xref: 'x',\n yref: 'paper',\n x0: band.x0,\n x1: band.x1,\n y0: 0,\n y1: 1,\n fillcolor: band.color || 'rgba(255, 200, 0, 0.08)',\n line: { width: 0 },\n opacity: band.opacity ?? 1,\n layer: 'below',\n });\n if (band.label) {\n annotations.push({\n x: (band.x0 + band.x1) / 2,\n y: band.labelY ?? 1.0,\n xref: 'x',\n yref: 'paper',\n text: band.label,\n showarrow: false,\n font: { size: 9, color: band.labelColor || 'rgba(255,255,255,0.55)' },\n xanchor: 'center',\n yanchor: 'bottom',\n });\n }\n }\n\n const firstYRef = Object.values(yRefByAxisId)[0] || 'y';\n for (const ref of referenceLines) {\n if (ref.value == null || !Number.isFinite(ref.value)) continue;\n const yRef = (ref.yAxisId && yRefByAxisId[ref.yAxisId]) || firstYRef;\n const color = ref.color || 'rgba(255, 120, 120, 0.75)';\n shapes.push({\n type: 'line',\n xref: 'paper',\n yref: yRef,\n x0: 0,\n x1: 1,\n y0: ref.value,\n y1: ref.value,\n line: {\n color,\n width: ref.lineWidth ?? 1.5,\n dash: dashMap[ref.lineStyle || 'dashed'] || 'dash',\n },\n layer: 'above',\n });\n if (ref.label) {\n annotations.push({\n x: ref.labelX ?? 0.015,\n y: ref.value,\n xref: 'paper',\n yref: yRef,\n text: ref.label,\n showarrow: false,\n font: { size: 10, color },\n xanchor: 'left',\n yanchor: 'bottom',\n bgcolor: 'rgba(20,22,26,0.6)',\n borderpad: 2,\n });\n }\n }\n\n for (const mark of verticalLines) {\n // `0` is a real x, so the test is null/undefined/NaN \u2014 never truthiness.\n if (mark == null || mark.x == null || (typeof mark.x === 'number' && !Number.isFinite(mark.x))) continue;\n const color = mark.color || 'rgba(255, 200, 0, 0.75)';\n shapes.push({\n type: 'line',\n xref: 'x',\n yref: 'paper',\n x0: mark.x,\n x1: mark.x,\n y0: 0,\n y1: 1,\n line: {\n color,\n width: mark.lineWidth ?? 1.5,\n dash: dashMap[mark.lineStyle || 'dashed'] || 'dash',\n },\n layer: 'above',\n });\n if (mark.label) {\n annotations.push({\n x: mark.x,\n y: mark.labelY ?? 1.0,\n xref: 'x',\n yref: 'paper',\n text: mark.label,\n showarrow: false,\n font: { size: 10, color },\n xanchor: 'left',\n yanchor: 'bottom',\n });\n }\n }\n\n return { shapes, annotations };\n}\n\n/**\n * Create a fan chart trace with confidence bands.\n * @param {Object} options\n * @param {Array} options.x - X-axis data (time)\n * @param {Array} options.upper - Upper bound data\n * @param {Array} options.lower - Lower bound data\n * @param {string} options.color - Band color\n * @param {number} options.opacity - Fill opacity\n * @param {string} [options.name] - Band name for legend\n * @returns {Array} Array of two traces (lower bound + fill to upper)\n */\nexport function buildFanBandTraces(options) {\n const { x, upper, lower, color, opacity = 0.2, name = '' } = options;\n\n // Lower bound line (invisible, for fill reference)\n const lowerTrace = {\n type: 'scatter',\n x,\n y: lower,\n mode: 'lines',\n line: { width: 0 },\n showlegend: false,\n hoverinfo: 'skip',\n };\n\n // Upper bound with fill to lower\n const upperTrace = {\n type: 'scatter',\n x,\n y: upper,\n mode: 'lines',\n line: { width: 0 },\n fill: 'tonexty',\n fillcolor: hexToRgba(color, opacity),\n name: name || `${(opacity * 100).toFixed(0)}% Band`,\n showlegend: !!name,\n };\n\n return [lowerTrace, upperTrace];\n}\n\n/**\n * Create a histogram trace.\n * @param {Object} options\n * @param {Array} options.x - Data values\n * @param {number} options.nbins - Number of bins\n * @param {string} options.color - Bar color\n * @param {string} [options.name] - Series name\n * @returns {Object} Plotly histogram trace\n */\nexport function buildHistogramTrace(options) {\n const { x, nbins = 20, color, name = 'Distribution' } = options;\n\n return {\n type: 'histogram',\n x,\n nbinsx: nbins,\n marker: { color },\n name,\n };\n}\n\n/**\n * Create a box plot trace.\n * @param {Object} options\n * @param {Array} options.y - Data values\n * @param {string} [options.x] - Category/time label\n * @param {string} options.color - Box color\n * @param {string} [options.name] - Series name\n * @returns {Object} Plotly box trace\n */\nexport function buildBoxTrace(options) {\n const { y, x = null, color, name = '' } = options;\n\n const trace = {\n type: 'box',\n y,\n marker: { color },\n name,\n boxpoints: false, // Don't show individual points\n };\n\n if (x !== null) {\n trace.x = Array.isArray(x) ? x : [x];\n }\n\n return trace;\n}\n\n/**\n * Create a heatmap trace.\n * @param {Object} options\n * @param {Array} options.z - 2D array of values\n * @param {Array} [options.x] - X labels\n * @param {Array} [options.y] - Y labels\n * @param {string} [options.colorscale] - Plotly colorscale name\n * @returns {Object} Plotly heatmap trace\n */\nexport function buildHeatmapTrace(options) {\n const { z, x = null, y = null, colorscale = 'RdBu' } = options;\n\n const trace = {\n type: 'heatmap',\n z,\n colorscale,\n showscale: true,\n };\n\n if (x) trace.x = x;\n if (y) trace.y = y;\n\n return trace;\n}\n\n// Delta sense, in the palette's own idiom (Solarized, per COLOR_PALETTE). A\n// caller whose metric is better when it falls \u2014 cost, latency, churn \u2014 passes\n// its own two colours rather than expecting a flag here: \"up is good\" is a\n// property of the measure, and this file has never been told what the measure\n// is.\nconst DELTA_UP = '#859900'; // Solarized green\nconst DELTA_DOWN = '#dc322f'; // Solarized red\n\n/**\n * Create a Plotly `indicator` trace \u2014 a big number, optionally with a gauge\n * arc under it and a delta against a reference.\n *\n * This is NOT reachable through `buildTrace`, and `indicator` is not in\n * `CHART_TYPES_2D`: `buildTrace`'s contract is two parallel arrays and an\n * indicator takes a single scalar, so offering it in the same dropdown would\n * offer a rendering that cannot consume what the dropdown's chart is bound to.\n *\n * The returned object is a plain literal and yours to extend \u2014 `domain` for\n * two indicators in one div, `number.prefix` / `number.valueformat` for\n * currency. Number formatting is deliberately not a parameter: a consumer that\n * already owns a value formatter and hands Plotly a second one shows the\n * currency symbol twice, and neither side knows the other did it.\n *\n * @param {Object} options\n * @param {number} options.value - The number to show\n * @param {number} [options.min] - Gauge floor (default 0)\n * @param {number} [options.max] - Gauge ceiling; null draws NO gauge\n * @param {string} [options.title] - Label above the number\n * @param {Array<{range: number[], color: string}>} [options.steps] - Banded background\n * @param {number|{value: number, color: string, width: number, thickness: number}} [options.threshold]\n * @param {string} [options.color] - The gauge bar colour\n * @param {number} [options.seriesIndex] - Palette index when `color` is absent\n * @param {number|{reference: number, relative: boolean, increasing: string, decreasing: string}} [options.delta]\n * @returns {Object} Plotly indicator trace\n */\nexport function buildIndicatorTrace(options) {\n const {\n value,\n min = 0,\n max = null,\n title = '',\n steps = null,\n threshold = null,\n color = null,\n seriesIndex = 0,\n delta = null,\n } = options;\n\n // A gauge with no ceiling has no arc to draw. Inventing one \u2014 twice the\n // value, the next round number \u2014 draws a chart that is quietly wrong about\n // the only thing a gauge communicates, so an absent `max` degrades to the\n // bare number instead.\n const hasGauge = typeof max === 'number' && Number.isFinite(max);\n\n // `0` is an ordinary reference \u2014 last month's total was zero \u2014 so the test\n // is `typeof`, never truthiness. Under a truthiness test `delta: 0` drops\n // the comparison the tile exists to draw, silently and only sometimes.\n const deltaSpec = typeof delta === 'number' ? { reference: delta }\n : (delta && typeof delta === 'object') ? delta\n : null;\n\n const parts = ['number'];\n if (hasGauge) parts.unshift('gauge');\n if (deltaSpec) parts.push('delta');\n\n const trace = {\n type: 'indicator',\n mode: parts.join('+'),\n value,\n };\n\n if (title) trace.title = { text: title };\n\n if (deltaSpec) {\n trace.delta = {\n reference: deltaSpec.reference,\n relative: deltaSpec.relative === true,\n increasing: { color: deltaSpec.increasing || DELTA_UP },\n decreasing: { color: deltaSpec.decreasing || DELTA_DOWN },\n };\n }\n\n if (hasGauge) {\n trace.gauge = {\n axis: { range: [min, max] },\n bar: { color: color || getSeriesColor(seriesIndex) },\n };\n // Passed through rather than derived. A band means something to the\n // consumer \u2014 a target, an SLA, a red zone \u2014 and this file cannot guess\n // where it sits.\n if (Array.isArray(steps) && steps.length) trace.gauge.steps = steps;\n\n if (threshold !== null && threshold !== undefined) {\n const t = typeof threshold === 'number' ? { value: threshold } : threshold;\n trace.gauge.threshold = {\n line: { color: t.color || DELTA_DOWN, width: t.width ?? 3 },\n thickness: t.thickness ?? 0.9,\n value: t.value,\n };\n }\n }\n\n return trace;\n}\n", "/**\n * downsample.js\n *\n * Client-side time-series decimation for the render path. A long live run\n * accumulates thousands of points per series; feeding all of them to\n * Plotly.react() every refresh is what makes a running dashboard crawl.\n * These helpers cap the points actually drawn while preserving the visual\n * shape.\n *\n * Two strategies, the usual pair on the server side as well (LTTB for one\n * line, stride decimation for a stream):\n *\n * \u2022 strideDownsampleShared \u2014 one set of indices applied to the shared x\n * axis and EVERY series. Cheap, gap-safe (nulls keep their slot), and\n * alignment-safe (all series sample the same x), so it works for\n * stacked/area charts and multi-series subplots. This is the default\n * used by the dashboard tiles.\n *\n * \u2022 lttb \u2014 Largest-Triangle-Three-Buckets for a single (x, y) line.\n * Higher visual fidelity (keeps peaks/troughs) but each series picks\n * its own x, so it's only safe for independent line/scatter traces\n * with finite y. Offered for callers that want it.\n */\n\n/**\n * Pick ~targetPoints evenly-spaced indices out of [0, n), always including\n * the first and last. Returns an ascending Int array; returns null when no\n * decimation is needed (n <= targetPoints) so callers can skip the copy.\n *\n * @param {number} n\n * @param {number} targetPoints\n * @returns {number[]|null}\n */\nexport function strideIndices(n, targetPoints) {\n if (!Number.isFinite(n) || n <= 0) return null;\n const target = Math.max(2, Math.floor(targetPoints) || 0);\n if (n <= target) return null;\n const step = (n - 1) / (target - 1);\n const idx = new Array(target);\n for (let i = 0; i < target; i++) idx[i] = Math.round(i * step);\n idx[target - 1] = n - 1; // pin the last point exactly\n // Dedupe (rounding can collide on dense targets) while staying ascending.\n let w = 0;\n for (let r = 0; r < idx.length; r++) {\n if (w === 0 || idx[r] > idx[w - 1]) idx[w++] = idx[r];\n }\n idx.length = w;\n return idx;\n}\n\n/**\n * Decimate a shared x axis plus a set of aligned series using one common\n * set of indices, so every series stays sampled at the same x (alignment-\n * and gap-safe). No-op (returns the inputs untouched) when under threshold.\n *\n * @param {Array<number>} time \u2014 shared x values\n * @param {Object<string, Array>} series \u2014 name \u2192 aligned value array\n * @param {number} targetPoints\n * @returns {{ time: Array<number>, series: Object<string, Array> }}\n */\nexport function strideDownsampleShared(time, series, targetPoints) {\n const idx = strideIndices(time?.length ?? 0, targetPoints);\n if (!idx) return { time, series };\n const dsTime = idx.map((i) => time[i]);\n const dsSeries = {};\n for (const [name, arr] of Object.entries(series || {})) {\n if (!Array.isArray(arr)) { dsSeries[name] = arr; continue; }\n dsSeries[name] = idx.map((i) => (i < arr.length ? arr[i] : null));\n }\n return { time: dsTime, series: dsSeries };\n}\n\n/**\n * Largest-Triangle-Three-Buckets for one line. Preserves the first and\n * last points and the most \"feature-bearing\" point per bucket. Assumes\n * ascending, finite x; y entries that are null/NaN are treated as 0 for\n * the area math (callers with gappy series should prefer the stride path).\n *\n * @param {Array<number>} x\n * @param {Array<number>} y\n * @param {number} threshold \u2014 target point count\n * @returns {{ x: Array<number>, y: Array<number> }}\n */\nexport function lttb(x, y, threshold) {\n const n = Math.min(x?.length ?? 0, y?.length ?? 0);\n const target = Math.floor(threshold) || 0;\n if (target <= 0 || target >= n) return { x: x.slice(0, n), y: y.slice(0, n) };\n if (target < 3) return { x: [x[0], x[n - 1]], y: [y[0], y[n - 1]] };\n\n const num = (v) => (Number.isFinite(v) ? v : 0);\n const outX = [x[0]];\n const outY = [y[0]];\n const bucketSize = (n - 2) / (target - 2);\n let a = 0;\n\n for (let i = 0; i < target - 2; i++) {\n let nextStart = Math.floor((i + 1) * bucketSize) + 1;\n let nextEnd = Math.min(Math.floor((i + 2) * bucketSize) + 1, n);\n if (nextEnd <= nextStart) nextEnd = Math.min(nextStart + 1, n);\n let avgX = 0, avgY = 0;\n const count = nextEnd - nextStart;\n for (let j = nextStart; j < nextEnd; j++) { avgX += x[j]; avgY += num(y[j]); }\n avgX /= count; avgY /= count;\n\n const curStart = Math.floor(i * bucketSize) + 1;\n const curEnd = Math.min(Math.floor((i + 1) * bucketSize) + 1, n);\n const ax = x[a], ay = num(y[a]);\n let maxArea = -1, chosen = curStart;\n for (let j = curStart; j < curEnd; j++) {\n const area = Math.abs((ax - avgX) * (num(y[j]) - ay) - (ax - x[j]) * (avgY - ay));\n if (area > maxArea) { maxArea = area; chosen = j; }\n }\n outX.push(x[chosen]); outY.push(y[chosen]);\n a = chosen;\n }\n\n outX.push(x[n - 1]); outY.push(y[n - 1]);\n return { x: outX, y: outY };\n}\n", "/**\n * plot_config.js \u2014 the shape of a plot, independent of what is being plotted.\n *\n * Subplot grid layouts, the default subplot, the legacy-format migration, and the\n * NaN strategies (gap / zero / hold / interpolate). Not one line of it knows what\n * an economy is.\n *\n * It lived in ui/js/notebook/cells/plot_cell.js \u2014 an EcoAgent notebook cell with\n * 60 domain words in it \u2014 and that single import was the only thing keeping the\n * plot windows out of @flexdesk/charts. Five modules imported these helpers THROUGH the\n * cell, which is how you end up with a chart library that depends on a notebook.\n *\n * plot_cell.js re-exports everything here, so its existing importers are unchanged.\n */\n\nimport { getSeriesColor } from './plotly_wrapper.js';\n\n\nlet _uid = 0;\nfunction uid(prefix = 'p') { return `${prefix}-${++_uid}-${Date.now().toString(36)}`; }\n\n/**\n * Apply NaN handling strategy to a data array.\n * @param {number[]} data\n * @param {'gap'|'zero'|'hold'|'interpolate'} strategy\n * @param {number[]} xData \u2014 for interpolation\n * @returns {Array}\n */\nfunction applyNanHandling(data, strategy, xData) {\n const isMissing = (v) => v === null || v === undefined || (typeof v === 'number' && !Number.isFinite(v));\n\n if (strategy === 'zero') return data.map(v => isMissing(v) ? 0 : v);\n\n if (strategy === 'hold') {\n const result = [];\n let last = null;\n for (const v of data) {\n if (isMissing(v)) result.push(last);\n else { last = v; result.push(v); }\n }\n return result;\n }\n\n if (strategy === 'interpolate') {\n const result = [...data];\n for (let i = 0; i < result.length; i++) {\n if (!isMissing(result[i])) continue;\n let left = -1, right = -1;\n for (let j = i - 1; j >= 0; j--) { if (!isMissing(result[j])) { left = j; break; } }\n for (let j = i + 1; j < result.length; j++) { if (!isMissing(result[j])) { right = j; break; } }\n if (left >= 0 && right >= 0 && xData) {\n const frac = (xData[i] - xData[left]) / (xData[right] - xData[left]);\n result[i] = result[left] + frac * (result[right] - result[left]);\n } else if (left >= 0) {\n result[i] = result[left];\n } else if (right >= 0) {\n result[i] = result[right];\n } else {\n result[i] = null;\n }\n }\n return result;\n }\n\n // 'gap' (default) \u2014 replace with null for Plotly gap rendering\n return data.map(v => isMissing(v) ? null : v);\n}\n\n// \u2500\u2500\u2500 Layout templates (matching figure_cell.js) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst PLOT_LAYOUTS = Object.freeze({\n '1x1': { label: 'Single', slots: 1, grid: { columns: '1fr', rows: '1fr' }, areas: [{ slot: 0, gridArea: '1/1/2/2' }] },\n '1x2': { label: 'Side by side', slots: 2, grid: { columns: '1fr 1fr', rows: '1fr' }, areas: [{ slot: 0, gridArea: '1/1/2/2' }, { slot: 1, gridArea: '1/2/2/3' }] },\n '2x1': { label: 'Stacked', slots: 2, grid: { columns: '1fr', rows: '1fr 1fr' }, areas: [{ slot: 0, gridArea: '1/1/2/2' }, { slot: 1, gridArea: '2/1/3/2' }] },\n '2x2': { label: '2\\u00d72 Grid', slots: 4, grid: { columns: '1fr 1fr', rows: '1fr 1fr' }, areas: [{ slot: 0, gridArea: '1/1/2/2' }, { slot: 1, gridArea: '1/2/2/3' }, { slot: 2, gridArea: '2/1/3/2' }, { slot: 3, gridArea: '2/2/3/3' }] },\n '1x3': { label: 'Three columns', slots: 3, grid: { columns: '1fr 1fr 1fr', rows: '1fr' }, areas: [{ slot: 0, gridArea: '1/1/2/2' }, { slot: 1, gridArea: '1/2/2/3' }, { slot: 2, gridArea: '1/3/2/4' }] },\n 'wide-top': { label: '1 + 2', slots: 3, grid: { columns: '1fr 1fr', rows: '1fr 1fr' }, areas: [{ slot: 0, gridArea: '1/1/2/3' }, { slot: 1, gridArea: '2/1/3/2' }, { slot: 2, gridArea: '2/2/3/3' }] },\n 'wide-bottom': { label: '2 + 1', slots: 3, grid: { columns: '1fr 1fr', rows: '1fr 1fr' }, areas: [{ slot: 0, gridArea: '1/1/2/2' }, { slot: 1, gridArea: '1/2/2/3' }, { slot: 2, gridArea: '2/1/3/3' }] },\n});\n\n/**\n * A new y axis with no series. Axis `index` 0, 2, 4, ... sits on the left,\n * 1, 3, 5, ... on the right.\n * @param {number} [index=0] - its place among the subplot's y axes\n */\nfunction makeDefaultYAxis(index = 0) {\n return {\n id: uid('y'),\n label: '',\n scale: 'linear',\n position: index % 2 === 0 ? 'left' : 'right',\n min: null,\n max: null,\n step: null,\n series: [],\n };\n}\n\n/**\n * A new series with no variable, coloured by its place in the subplot.\n * @param {number} [index=0] - how many series the subplot already has\n */\nfunction makeDefaultSeries(index = 0) {\n return {\n id: uid('s'),\n variable: '',\n label: '',\n color: getSeriesColor(index),\n lineWidth: 2,\n lineStyle: 'solid',\n stackGroup: null,\n };\n}\n\nfunction makeDefaultSubplot(index) {\n return {\n id: uid('sp'),\n displayName: '',\n chartType: 'line',\n legendPosition: 'hidden',\n interpolation: 'linear',\n nanHandling: 'gap',\n showDataPoints: false,\n xAxis: { useTime: true, variable: '' },\n zAxis: null,\n yAxes: [makeDefaultYAxis(0)],\n };\n}\n\nfunction migrateData(data) {\n // Already in multi-layout format\n if (data?.layout && Array.isArray(data?.subplots)) {\n // Migrate caption \u2192 description (old field name)\n if ('caption' in data && !('description' in data)) {\n data.description = data.caption;\n data.caption = '';\n }\n return data;\n }\n\n // Migrate legacy single-chart format \u2192 multi-layout with one subplot\n const legacySingle = migrateSingleChart(data);\n return {\n layout: '1x1',\n subplots: [{ id: uid('sp'), ...legacySingle }],\n caption: '',\n description: data?.caption ?? data?.description ?? '',\n doc: data?.doc ?? '',\n };\n}\n\n/** Migrate legacy flat series[]/variables[] to yAxes[] single-chart format. */\nfunction migrateSingleChart(data) {\n if (data?.yAxes) {\n return {\n displayName: data.displayName ?? '',\n chartType: data.chartType ?? 'line',\n legendPosition: data.legendPosition ?? 'hidden',\n interpolation: data.interpolation ?? 'linear',\n nanHandling: data.nanHandling ?? 'gap',\n showDataPoints: data.showDataPoints ?? false,\n yAxes: data.yAxes,\n };\n }\n\n const series = data?.series ?? data?.variables?.map((v, i) => ({\n variable: v, label: '', color: getSeriesColor(i),\n })) ?? [];\n\n return {\n displayName: data?.title ?? data?.displayName ?? '',\n chartType: data?.chartType ?? data?.widgetType ?? 'line',\n legendPosition: data?.legendPosition ?? 'hidden',\n interpolation: data?.interpolation ?? 'linear',\n nanHandling: data?.nanHandling ?? 'gap',\n showDataPoints: data?.showDataPoints ?? false,\n yAxes: [{\n ...makeDefaultYAxis(0),\n label: data?.yLabel ?? '',\n series: series.map((s, i) => {\n const d = makeDefaultSeries(i);\n return {\n id: s.id ?? d.id,\n variable: s.variable ?? d.variable,\n label: s.label ?? d.label,\n color: s.color ?? d.color,\n lineWidth: s.lineWidth ?? d.lineWidth,\n lineStyle: s.lineStyle ?? d.lineStyle,\n stackGroup: s.stackGroup ?? d.stackGroup,\n ...(s.overlay ? { overlay: s.overlay } : {}),\n };\n }),\n }],\n };\n}\n\nexport {\n uid, applyNanHandling, PLOT_LAYOUTS, makeDefaultSubplot, makeDefaultYAxis, makeDefaultSeries,\n migrateData, migrateSingleChart,\n};\n", "/**\n * series_transforms.js \u2014 derived series an embedder supplies: a trend, a moving\n * average, a decomposition. @flexdesk/charts ships none of its own.\n *\n * A transform is a description plus an async function:\n *\n * const seriesTransforms = {\n * movingAverage: {\n * label: 'Moving average',\n * params: { window: { label: 'Window', default: 5, min: 1, step: 1 } },\n * outputs: {\n * mean: { label: 'Mean', suffix: ' (MA)', lineStyle: 'dashed' },\n * },\n * run: async (y, params) => ({ mean: rollingMean(y, params.window) }),\n * },\n * };\n *\n * `run(y, params, context)` resolves `{ [output]: number[] }`. It is called\n * ONCE per eligible trace (a 2-D line/scatter trace) for each transform with at\n * least one output switched on, and every switched-on output it returns is\n * drawn as an extra trace in the source trace's colour, named\n * `<source name><suffix>`, with the output's `lineStyle` (solid | dashed |\n * dotted) and `lineWidth`.\n *\n * `y` is the drawn values (after the subplot's NaN handling and whatever the\n * embedder's `resolveSeries` did, such as a rebase). `context` (0.17.8) says\n * which series they are:\n *\n * { series, // the subplot's series entry the trace was drawn from\n * // (its variable, scenario, ...); null when unknown\n * subplot, // the subplot config\n * results, // the results the figure was drawn from, or null\n * resolveSeries } // the `(series, results, subplot) => { y, x? }` the\n * // figure was drawn with, or null\n *\n * so a transform can look the same series up elsewhere (a baseline scenario)\n * and resolve it the same way. renderPlotGrid (and so PlotPopoutWindow) runs\n * transforms on the same traces as before 0.17.8 (overlays included, derived\n * traces never); a trace drawn from one of the subplot's series gets that\n * series, any other (an overlay) gets `series: null`. A transform written as\n * `run(y, params)` ignores the third argument and works as before.\n *\n * A parameter is a number field by default:\n *\n * window: { label: 'Window', default: 5, min: 1, step: 1 }\n *\n * or, declared `type: 'choice'` (0.17.8), a select over `options`: an array of\n * `{ value, label }`, or a function `(subplot) => [{ value, label }]` called\n * when the controls are drawn (and when the parameter needs its default):\n *\n * baseline: { label: 'Compare with', type: 'choice',\n * options: () => scenarios.map((s) => ({ value: s.id, label: s.name })) }\n *\n * The chosen value is saved and passed to `run` like a number. Without a\n * `default` and with nothing saved, a choice is its first enabled option.\n *\n * What is switched on lives in the subplot, under `subplot.transforms`:\n *\n * subplot.transforms = { movingAverage: { outputs: { mean: true }, params: { window: 7 } } }\n *\n * A transform that throws, rejects or resolves something that is not an object\n * is skipped for that trace; the figure is drawn without it.\n */\n\nimport { buildTrace } from './chart_types.js';\nimport { flatChoices, selectBox } from '../ui/components/choice_controls.js';\n\n/** Whether a parameter spec is a choice (a select) rather than a number. */\nconst isChoice = (spec) => spec?.type === 'choice';\n\n/** A choice parameter's options for `subplot`: its array, or what its function returns. */\nfunction choiceOptions(spec, subplot) {\n const options = typeof spec.options === 'function' ? spec.options(subplot) : spec.options;\n return Array.isArray(options) ? options : [];\n}\n\n/**\n * A choice parameter's value when none is declared or saved: the option\n * selectBox selects for it, its first enabled one, `{ group, options }`\n * entries flattened in order (the first of all when every one is disabled).\n */\nfunction firstChoice(spec, subplot) {\n const flat = flatChoices(choiceOptions(spec, subplot));\n return (flat.find((o) => !o.disabled) ?? flat[0])?.value;\n}\n\n/** A transform's parameter values: its declared defaults under the subplot's own. */\nfunction resolveParams(transform, state, subplot) {\n const saved = state?.params ?? {};\n const params = {};\n for (const [name, spec] of Object.entries(transform.params ?? {})) {\n params[name] = spec?.default;\n if (isChoice(spec) && spec.default === undefined && saved[name] === undefined) {\n params[name] = firstChoice(spec, subplot);\n }\n }\n return { ...params, ...saved };\n}\n\n/** The output names of `transform` that `state` switches on, in declared order. */\nfunction enabledOutputs(transform, state) {\n return Object.keys(transform.outputs ?? {}).filter((name) => state?.outputs?.[name] === true);\n}\n\n/** A trace a transform may run on: 2-D, line or scatter, with a y array. */\nfunction isEligible(trace) {\n const type = trace.type ?? 'scatter';\n return (type === 'scatter' || type === 'scattergl') && Array.isArray(trace.y);\n}\n\n/**\n * The derived traces for one subplot's figure.\n *\n * @param {Object[]} traces - The figure's Plotly traces so far (not modified).\n * @param {Object} subplot - The subplot config; reads `subplot.transforms`.\n * @param {Object|null} seriesTransforms - `{ [id]: transform }`, or null for none.\n * @param {Object} [options]\n * @param {Function} [options.onError] - `({ transformId, traceName, error })`,\n * called for each skipped run.\n * @param {Function} [options.seriesOf] - `(trace) => series | null`: the series\n * config a trace was drawn from, passed as `context.series` (null for a\n * trace it names none for, and for every trace without it). It does not\n * choose the sources: every eligible trace is run on, as before.\n * @param {Object} [options.results] - The results the figure was drawn from\n * (`context.results`).\n * @param {Function} [options.resolveSeries] - The resolver the figure was drawn\n * with (`context.resolveSeries`).\n * @returns {Promise<Object[]>} The extra traces, in transform then trace order.\n */\nasync function deriveSeriesTraces(traces, subplot, seriesTransforms,\n { onError, seriesOf, results, resolveSeries } = {}) {\n const derived = [];\n if (!seriesTransforms) return derived;\n const sources = traces.filter(isEligible)\n .map((trace) => ({ trace, series: typeof seriesOf === 'function' ? (seriesOf(trace) ?? null) : null }));\n\n for (const [transformId, transform] of Object.entries(seriesTransforms)) {\n const state = subplot?.transforms?.[transformId];\n const outputs = enabledOutputs(transform, state);\n if (!outputs.length || typeof transform?.run !== 'function') continue;\n const params = resolveParams(transform, state, subplot);\n\n for (const { trace: source, series } of sources) {\n const context = { series, subplot, results: results ?? null, resolveSeries: resolveSeries ?? null };\n let result;\n try {\n result = await transform.run(source.y, params, context);\n } catch (error) {\n onError?.({ transformId, traceName: source.name, error });\n continue;\n }\n if (!result || typeof result !== 'object') {\n onError?.({ transformId, traceName: source.name,\n error: new Error(`transform \"${transformId}\" resolved no outputs`) });\n continue;\n }\n const color = source.line?.color || source.marker?.color;\n for (const name of outputs) {\n const y = result[name];\n if (!Array.isArray(y)) continue;\n const spec = transform.outputs[name];\n derived.push({\n ...buildTrace({\n chartType: 'line',\n x: source.x,\n y,\n name: `${source.name}${spec.suffix ?? ` (${spec.label ?? name})`}`,\n color,\n lineWidth: spec.lineWidth ?? 2,\n lineStyle: spec.lineStyle ?? 'solid',\n yAxisId: source.yaxis || 'y',\n }),\n showlegend: true,\n });\n }\n }\n }\n return derived;\n}\n\n/**\n * The controls for `seriesTransforms` in a subplot's config: per transform, a\n * toggle for each output and, for each parameter, a number field or, for a\n * `type: 'choice'` parameter, a select (choice_controls' selectBox). They edit\n * `subplot.transforms` in place and call `onChange()` after every edit. With no\n * transforms (null or `{}`) nothing is rendered.\n *\n * @param {HTMLElement} container\n * @param {Object} subplot\n * @param {Object|null} seriesTransforms\n * @param {Object} [options]\n * @param {Function} [options.onChange]\n * @returns {{ dispose: Function }}\n */\nfunction renderSeriesTransformControls(container, subplot, seriesTransforms, { onChange } = {}) {\n const entries = Object.entries(seriesTransforms ?? {});\n if (!entries.length) return { dispose() {} };\n\n const root = document.createElement('div');\n root.className = 'twm-series-transforms';\n\n const stateOf = (transformId) => {\n subplot.transforms ??= {};\n subplot.transforms[transformId] ??= {};\n return subplot.transforms[transformId];\n };\n\n for (const [transformId, transform] of entries) {\n const group = document.createElement('fieldset');\n group.className = 'twm-series-transforms__group';\n const legend = document.createElement('legend');\n legend.className = 'twm-series-transforms__label';\n legend.textContent = transform.label ?? transformId;\n group.appendChild(legend);\n\n const paramInputs = [];\n const syncDisabled = () => {\n const on = enabledOutputs(transform, subplot.transforms?.[transformId]).length > 0;\n for (const input of paramInputs) input.disabled = !on;\n };\n\n for (const [name, spec] of Object.entries(transform.outputs ?? {})) {\n const row = document.createElement('label');\n row.className = 'twm-series-transforms__row';\n const box = document.createElement('input');\n box.type = 'checkbox';\n box.checked = subplot.transforms?.[transformId]?.outputs?.[name] === true;\n box.addEventListener('change', () => {\n const state = stateOf(transformId);\n state.outputs = { ...(state.outputs ?? {}), [name]: box.checked };\n syncDisabled();\n onChange?.();\n });\n const text = document.createElement('span');\n text.textContent = spec?.label ?? name;\n row.append(box, text);\n group.appendChild(row);\n }\n\n for (const [name, spec] of Object.entries(transform.params ?? {})) {\n const row = document.createElement('label');\n row.className = 'twm-series-transforms__row';\n const text = document.createElement('span');\n text.textContent = spec?.label ?? name;\n const writeParam = (value) => {\n const state = stateOf(transformId);\n const params = { ...(state.params ?? {}) };\n if (value === undefined) delete params[name];\n else params[name] = value;\n state.params = params;\n onChange?.();\n };\n const saved = subplot.transforms?.[transformId]?.params?.[name];\n\n if (isChoice(spec)) {\n const current = saved ?? spec.default ?? firstChoice(spec, subplot);\n const choice = selectBox(choiceOptions(spec, subplot), current, {\n label: spec?.label ?? name,\n valueAttr: 'value',\n className: 'twm-series-transforms__param twm-series-transforms__select',\n });\n choice.box.addEventListener('change', () => {\n const value = choice.valueOf();\n // Redrawn with the chosen value, as settings do: a stale\n // '(not found)' entry goes once an offered option is picked.\n choice.setOptions(choiceOptions(spec, subplot), value);\n writeParam(value);\n });\n paramInputs.push(choice.box);\n row.append(text, choice.box);\n group.appendChild(row);\n continue;\n }\n\n const input = document.createElement('input');\n input.type = 'number';\n input.className = 'twm-series-transforms__param';\n for (const attr of ['min', 'max', 'step']) {\n if (spec?.[attr] != null) input[attr] = String(spec[attr]);\n }\n const current = saved ?? spec?.default;\n input.value = current == null ? '' : String(current);\n input.addEventListener('change', () => {\n const value = parseFloat(input.value);\n writeParam(Number.isFinite(value) ? value : undefined);\n });\n paramInputs.push(input);\n row.append(text, input);\n group.appendChild(row);\n }\n\n syncDisabled();\n root.appendChild(group);\n }\n\n container.appendChild(root);\n return { dispose() { root.remove(); } };\n}\n\nexport { deriveSeriesTraces, renderSeriesTransformControls };\n", "/**\n * plot_grid.js \u2014 draw a plot config into any container.\n *\n * A plot config (plot_config.js: `{ layout, subplots }`) is a grid of subplots,\n * each with one or more y-axes of series. `renderPlotGrid` lays the grid out\n * from PLOT_LAYOUTS, draws one Plotly figure per subplot and keeps them drawn:\n *\n * const grid = renderPlotGrid(el, plotConfig, { time, series }, { overlays });\n * await grid.update({ results: next }); // new data, same grid\n * grid.resize(); // after the container changed size\n * grid.dispose(); // purge every figure, remove the grid\n *\n * Per subplot it draws: the chart type, the interpolation, data points, stack\n * groups, every y-axis (left/right, linear/log, min/max/step), reference lines\n * and shaded bands, the NaN strategy, the x-axis clipped to the results' time\n * range \u2014 or an x variable instead of time (`subplot.xAxis = { useTime: false,\n * variable }`) \u2014 per-series overlay data, injected series transforms, and\n * whatever extra traces the embedder derives. A subplot with nothing to draw\n * shows the empty message; a grid slot with no subplot shows another.\n *\n * A figure is drawn only into a cell that is in the document and has a size.\n * One that is not (a hidden tab, a window not yet shown) is remembered and\n * drawn the next time the grid is resized, which its own ResizeObserver does\n * when the container gets a size.\n *\n * It was PlotPopoutWindow's private renderer; the window now calls this.\n */\n\nimport { createRafResizeObserver } from '../ui/utils/raf_resize_observer.js';\nimport { ensurePlotly } from './plotly_wrapper.js';\nimport { buildTrace, buildYAxisLayout, buildLegendLayout, buildOverlayShapes } from './chart_types.js';\nimport { PLOT_LAYOUTS, applyNanHandling } from './plot_config.js';\nimport { deriveSeriesTraces } from './series_transforms.js';\n\n/** The figure colours and font. `options.theme` overrides any of them. */\nconst PLOT_GRID_THEME = Object.freeze({\n fontFamily: 'Inter, -apple-system, BlinkMacSystemFont, sans-serif',\n fontColor: '#cccccc',\n fontSize: 11,\n paperBackground: 'transparent',\n plotBackground: 'transparent',\n gridColor: 'rgba(255,255,255,0.05)',\n lineColor: 'rgba(255,255,255,0.08)',\n tickColor: 'rgba(255,255,255,0.3)',\n zeroLineColor: 'rgba(255,255,255,0.06)',\n hoverBackground: '#1e2228',\n hoverBorder: '#444444',\n});\n\nconst OVERLAY_DASH = { dashed: 'dash', dotted: 'dot', solid: 'solid' };\n\n/**\n * The default series lookup: `results.series[series._resultKey ?? series.variable]`,\n * then `series.variable`, then the variable without its `prefix.`. Its own x is\n * `series._resultTime` when it has one.\n *\n * @param {Object} series - A series of a subplot's y-axis.\n * @param {{ time?: number[], series?: Object }} results\n * @returns {{ y: number[], x?: number[] } | null}\n */\nfunction resolveSeriesData(series, results) {\n const table = results?.series;\n const variable = series?.variable;\n if (!table || !variable) return null;\n let y = table[series._resultKey ?? variable];\n if (!y && series._resultKey) y = table[variable];\n if (!y) {\n const dot = variable.indexOf('.');\n if (dot >= 0) y = table[variable.slice(dot + 1)];\n }\n if (!y) return null;\n return series._resultTime ? { y, x: series._resultTime } : { y };\n}\n\n/**\n * Draw `plotConfig` into `container`.\n *\n * @param {HTMLElement} container - Receives one `.twm-plot-grid` child.\n * @param {{ layout: string, subplots: Object[] }} plotConfig - Already migrated (migrateData).\n * @param {{ time: number[], series: Object } | null} results - null: every subplot is empty.\n * @param {Object} [options]\n * @param {Function} [options.resolveSeries] - `(series, results, subplot) => { y, x? } | null`;\n * default resolveSeriesData. Also resolves the x variable, as `{ variable }`.\n * @param {Object} [options.overlays] - `{ [series.id]: { years, values } }`, drawn for\n * every series with an `overlay` description.\n * @param {Object} [options.seriesTransforms] - `{ [id]: transform }` (series_transforms.js).\n * Each runs on every line/scatter trace (overlays included, derived traces\n * not) as `run(y, params, { series, subplot, results, resolveSeries })`,\n * `series` being the subplot's series entry the trace was drawn from, or\n * null for an overlay.\n * @param {Function} [options.onTransformError] - `({ transformId, traceName, error })`.\n * @param {Function} [options.derivedTraces] - `(traces, subplot, { results, index })\n * => trace[] | Promise<trace[]>`: extra traces appended to a subplot's figure.\n * @param {Set<string>|string[]} [options.hiddenSeries] - Trace names not to draw.\n * @param {Object} [options.theme] - Overrides for PLOT_GRID_THEME.\n * @param {boolean} [options.alwaysShowLegend=false] - Draw a 'hidden' legend at the top.\n * @param {Object} [options.layout] - Plotly layout fields merged over every figure's.\n * @param {string} [options.emptyMessage='No data yet.']\n * @param {string} [options.noSubplotMessage='No subplot configured.']\n * @param {Function} [options.onError] - `({ index, error })` when drawing a subplot\n * throws \u2014 on an update or on a resize that draws a deferred one; that\n * subplot shows the empty message.\n * @returns {{ update: Function, resize: Function, dispose: Function,\n * readonly charts: HTMLElement[], readonly plotted: HTMLElement[] }}\n */\nfunction renderPlotGrid(container, plotConfig, results, options = {}) {\n const opts = {\n resolveSeries: resolveSeriesData,\n overlays: null,\n seriesTransforms: null,\n onTransformError: null,\n derivedTraces: null,\n hiddenSeries: null,\n theme: null,\n alwaysShowLegend: false,\n layout: null,\n emptyMessage: 'No data yet.',\n noSubplotMessage: 'No subplot configured.',\n onError: null,\n ...options,\n };\n let config = plotConfig;\n let data = results;\n let disposed = false;\n let cells = [];\n let cellsLayout = null;\n /**\n * Per cell: the latest draw's token, from one grid-wide counter that a\n * rebuild never resets, so no draw for an old layout shares a token with a\n * draw for the new one. An older draw that resolves late is dropped.\n */\n let tokens = [];\n let lastToken = 0;\n /** Cells whose last draw found them detached or zero-size. */\n const deferred = new Set();\n\n const grid = document.createElement('div');\n grid.className = 'twm-plot-grid';\n container.appendChild(grid);\n\n const observer = createRafResizeObserver(() => resize());\n observer.observe(grid);\n\n /** Cells Plotly has been asked to draw into: every one of them is purged. */\n const plotted = new Set();\n /** Cells whose latest Plotly draw finished: they show a figure. */\n const drawn = new Set();\n const hasPlot = (cell) => plotted.has(cell);\n const purgeCell = (cell) => {\n drawn.delete(cell);\n if (!plotted.delete(cell)) return;\n try { globalThis.Plotly?.purge(cell); } catch (_) { /* already gone */ }\n };\n\n function buildCells() {\n for (const cell of cells) purgeCell(cell);\n grid.replaceChildren();\n const tmpl = PLOT_LAYOUTS[config?.layout] || PLOT_LAYOUTS['1x1'];\n grid.style.gridTemplateColumns = tmpl.grid.columns;\n grid.style.gridTemplateRows = tmpl.grid.rows;\n cells = tmpl.areas.map(({ gridArea }) => {\n const cell = document.createElement('div');\n cell.className = 'twm-plot-grid__cell';\n cell.style.gridArea = gridArea;\n grid.appendChild(cell);\n return cell;\n });\n cellsLayout = config?.layout;\n tokens = cells.map(() => 0);\n deferred.clear();\n }\n\n function showMessage(cell, text) {\n purgeCell(cell);\n const msg = document.createElement('div');\n msg.className = 'twm-plot-no-data';\n msg.textContent = text;\n cell.replaceChildren(msg);\n }\n\n const theme = () => ({ ...PLOT_GRID_THEME, ...(opts.theme ?? {}) });\n const isHidden = (name) => {\n const h = opts.hiddenSeries;\n if (!h) return false;\n return typeof h.has === 'function' ? h.has(name) : h.includes(name);\n };\n const axisColours = (t) => ({\n gridcolor: t.gridColor, linecolor: t.lineColor,\n tickcolor: t.tickColor, zerolinecolor: t.zeroLineColor,\n });\n\n /** The traces and layout of one subplot, or null when it has nothing to draw. */\n async function buildFigure(sp, index) {\n // No results is the empty message, whatever is hidden.\n if (!data) return null;\n const t = theme();\n const time = data.time ?? [];\n const traces = [];\n const layoutAxes = {};\n const yRefByAxisId = {};\n /** The subplot's own series (overlays and derived traces aside), and how many are hidden. */\n let ownCount = 0;\n let hiddenCount = 0;\n /** Each trace drawn from one of the subplot's series, to that series (a transform's context.series). */\n const seriesByTrace = new Map();\n\n const useX = sp.xAxis && sp.xAxis.useTime === false && sp.xAxis.variable;\n const xData = useX\n ? (opts.resolveSeries({ variable: sp.xAxis.variable }, data, sp)?.y ?? time)\n : time;\n\n const yAxes = sp.yAxes ?? [];\n yAxes.forEach((axis, a) => {\n const n = a + 1;\n const yAxisKey = n === 1 ? 'yaxis' : `yaxis${n}`;\n const yRef = n === 1 ? 'y' : `y${n}`;\n if (axis.id) yRefByAxisId[axis.id] = yRef;\n\n layoutAxes[yAxisKey] = {\n ...buildYAxisLayout({\n axisId: yAxisKey,\n title: axis.label || '',\n position: axis.position || 'left',\n scaleType: axis.scale || 'linear',\n min: axis.min ?? null,\n max: axis.max ?? null,\n step: axis.step ?? null,\n showGrid: yAxes.length === 1,\n axisPosition: n > 1 ? (axis.position === 'right' ? 1 : 0) : null,\n }),\n ...axisColours(t),\n };\n\n for (const s of axis.series ?? []) {\n if (!s.variable) continue;\n const label = s.label || s.variable;\n ownCount++;\n if (isHidden(label)) { hiddenCount++; continue; }\n\n const resolved = opts.resolveSeries(s, data, sp);\n if (!resolved?.y) continue;\n const x = resolved.x ?? xData;\n const y = Array.isArray(resolved.y)\n ? applyNanHandling(resolved.y, sp.nanHandling ?? 'gap', x)\n : resolved.y;\n const trace = buildTrace({\n chartType: sp.chartType || 'line',\n x,\n y,\n name: label,\n color: s.color,\n lineWidth: s.lineWidth ?? 2,\n lineStyle: s.lineStyle ?? 'solid',\n interpolation: sp.interpolation ?? 'linear',\n yAxisId: yRef,\n showMarkers: sp.showDataPoints ?? false,\n stackGroup: s.stackGroup ?? null,\n });\n traces.push(trace);\n seriesByTrace.set(trace, s);\n\n const overlay = s.overlay ? opts.overlays?.[s.id] : null;\n if (!overlay?.years?.length) continue;\n const ov = s.overlay;\n const ovLabel = ov.label || `${label} (actual)`;\n if (isHidden(ovLabel)) continue;\n const ovTrace = {\n type: 'scatter',\n mode: ov.mode || 'markers+lines',\n x: overlay.years,\n y: overlay.values,\n name: ovLabel,\n yaxis: yRef === 'y' ? undefined : yRef,\n line: { color: ov.color || s.color, width: ov.lineWidth ?? 2,\n dash: OVERLAY_DASH[ov.lineStyle] || 'dash' },\n marker: { color: ov.color || s.color, size: 4, symbol: 'circle' },\n showlegend: true,\n };\n // A stacked-percent chart stacks its overlays too, in a group of\n // their own, so they read on the same 0..1 scale.\n if ((sp.chartType || 'line') === 'area-stacked') {\n ovTrace.stackgroup = `overlay-${yRef}`;\n ovTrace.groupnorm = 'fraction';\n ovTrace.fill = 'none';\n ovTrace.mode = 'lines';\n }\n traces.push(ovTrace);\n }\n });\n\n traces.push(...await deriveSeriesTraces(traces, sp, opts.seriesTransforms, {\n onError: opts.onTransformError ?? undefined,\n seriesOf: (trace) => seriesByTrace.get(trace) ?? null,\n results: data,\n resolveSeries: opts.resolveSeries,\n }));\n if (opts.derivedTraces) {\n const extra = await opts.derivedTraces(traces, sp, { results: data, index });\n if (Array.isArray(extra)) traces.push(...extra);\n }\n\n // Nothing to draw is the empty message \u2014 unless there are results and\n // every one of the subplot's own series is hidden: then it is an empty\n // figure, so the viewer can tell \"hidden\" from \"no data\".\n if (traces.length === 0 && !(ownCount > 0 && hiddenCount === ownCount)) return null;\n\n const legendPos = opts.alwaysShowLegend && (sp.legendPosition ?? 'hidden') === 'hidden'\n ? 'top' : (sp.legendPosition ?? 'hidden');\n const xRange = !useX && time.length >= 2 ? [time[0], time[time.length - 1]] : undefined;\n const { shapes, annotations } = buildOverlayShapes({\n referenceLines: sp.referenceLines,\n shadedBands: sp.shadedBands,\n yRefByAxisId,\n });\n const font = { family: t.fontFamily, color: t.fontColor };\n\n const layout = {\n ...layoutAxes,\n ...(shapes.length ? { shapes } : {}),\n ...(annotations.length ? { annotations } : {}),\n xaxis: {\n ...(useX ? { title: { text: sp.xAxis.label || sp.xAxis.variable, font: { size: t.fontSize } } } : {}),\n ...axisColours(t),\n automargin: true,\n ...(xRange ? { range: xRange } : {}),\n },\n ...buildLegendLayout(legendPos),\n paper_bgcolor: t.paperBackground,\n plot_bgcolor: t.plotBackground,\n font: { ...font, size: t.fontSize },\n margin: { t: 10, r: 20, b: 40, l: 50 },\n hoverlabel: { bgcolor: t.hoverBackground, bordercolor: t.hoverBorder, font },\n ...(opts.layout ?? {}),\n };\n return { traces, layout };\n }\n\n const hasSize = (cell) => cell.isConnected && cell.offsetWidth > 0 && cell.offsetHeight > 0;\n\n /** Draw cell `index`; resolves true when a figure was drawn. */\n async function drawCell(index) {\n const cell = cells[index];\n const token = ++lastToken;\n tokens[index] = token;\n const current = () => !disposed && cells[index] === cell && tokens[index] === token;\n const sp = config?.subplots?.[index];\n if (!sp) { showMessage(cell, opts.noSubplotMessage); deferred.delete(index); return false; }\n\n const figure = await buildFigure(sp, index);\n if (!current()) return false;\n if (!figure) { showMessage(cell, opts.emptyMessage); deferred.delete(index); return false; }\n\n if (!hasSize(cell)) { deferred.add(index); return false; }\n deferred.delete(index);\n\n const Plotly = await ensurePlotly();\n if (!current()) return false;\n if (!hasPlot(cell)) cell.replaceChildren();\n plotted.add(cell);\n try {\n await Plotly.react(cell, figure.traces, figure.layout, { responsive: true, displayModeBar: false });\n if (plotted.has(cell)) drawn.add(cell);\n return true;\n } catch (_) {\n // Plotly throws when the cell is removed mid-draw.\n drawn.delete(cell);\n return false;\n }\n }\n\n /**\n * Draw cell `index` and handle a failure: a resolver, transform or\n * derivedTraces that throws costs its own subplot only \u2014 it shows the empty\n * message and is reported to onError. Every draw goes through here.\n */\n function drawCellOrFail(index) {\n const cell = cells[index];\n const pending = drawCell(index);\n const token = tokens[index];\n return pending.catch((error) => {\n if (disposed) return false;\n if (cells[index] === cell && tokens[index] === token) {\n deferred.delete(index);\n showMessage(cell, opts.emptyMessage);\n }\n opts.onError?.({ index, error });\n return false;\n });\n }\n\n async function drawAll() {\n if (disposed) return false;\n if (cellsLayout !== config?.layout || !cells.length) buildCells();\n const results = await Promise.all(cells.map((_, i) => drawCellOrFail(i)));\n return results.some(Boolean);\n }\n\n /**\n * Change what is drawn and redraw. Every field is optional; omitted ones keep\n * their value. A config with another layout rebuilds the grid.\n *\n * @param {Object} [patch]\n * @param {Object} [patch.plotConfig]\n * @param {Object|null} [patch.results]\n * @param {Object|null} [patch.overlays]\n * @param {Set<string>|string[]|null} [patch.hiddenSeries]\n * @returns {Promise<boolean>} whether any figure was drawn\n */\n function update(patch = {}) {\n if (disposed) return Promise.resolve(false);\n if ('plotConfig' in patch) config = patch.plotConfig;\n if ('results' in patch) data = patch.results;\n if ('overlays' in patch) opts.overlays = patch.overlays;\n if ('hiddenSeries' in patch) opts.hiddenSeries = patch.hiddenSeries;\n return drawAll();\n }\n\n /** Fit every figure to its cell, and draw the ones that were waiting for a size. */\n function resize() {\n if (disposed) return;\n for (const index of [...deferred]) {\n if (!hasSize(cells[index])) continue;\n drawCellOrFail(index);\n }\n const Plotly = globalThis.Plotly;\n if (!Plotly?.Plots?.resize) return;\n for (const cell of cells) {\n if (hasPlot(cell) && hasSize(cell)) {\n Promise.resolve().then(() => Plotly.Plots.resize(cell)).catch(() => {});\n }\n }\n }\n\n /** Purge every figure and remove the grid. Later calls do nothing. */\n function dispose() {\n if (disposed) return;\n disposed = true;\n observer.disconnect();\n for (const cell of cells) purgeCell(cell);\n cells = [];\n deferred.clear();\n grid.remove();\n }\n\n drawAll();\n\n return {\n update,\n resize,\n dispose,\n /** The cells, one per grid slot, in layout order. */\n get charts() { return [...cells]; },\n /**\n * The cells that show a figure now, in layout order \u2014 however it got\n * there: an update, or a deferred draw on a resize.\n */\n get plotted() { return cells.filter((cell) => drawn.has(cell)); },\n };\n}\n\nexport { renderPlotGrid, resolveSeriesData, PLOT_GRID_THEME };\n", "/**\n * Plot Popout Window\n *\n * Opens a plot in a separate draggable/resizable ManagedWindow with two tabs:\n * - Plot tab: Interactive Plotly chart grid with modebar controls\n * - Data tab: Table showing all series using the unified DataTable component\n *\n * Uses the PlotCell data model (multi-layout subplots) as its canonical format.\n * All plot window contexts (notebook, dashboard, documentation) use this single\n * implementation.\n *\n * Features:\n * - Multi-subplot grid layouts (1x1, 1x2, 2x1, 2x2, 1x3, wide-top, wide-bottom)\n * - Series visibility toggle panel\n * - Zoom/pan toolbar with zoom in/out, autoscale, reset\n * - CSV and PNG export through the host's dialogs (else a browser download)\n * - NotificationCenter integration for user feedback\n * - Live streaming updates while the data source is running\n * - Derived series from injected transforms (`seriesTransforms`)\n * - ETL actuals overlay support\n *\n * The figures are drawn by renderPlotGrid (plot_grid.js); this window adds the\n * tabs, the toolbar, the series toggles and the data table around them.\n */\n\nimport { ManagedWindow } from '../ui/components/managed_window.js';\nimport { DataTable } from '../ui/components/data_table.js';\nimport { createRafResizeObserver } from '../ui/utils/raf_resize_observer.js';\nimport {\n ensurePlotly,\n purge,\n getSeriesColor,\n} from './plotly_wrapper.js';\nimport { migrateData } from './plot_config.js';\nimport { renderPlotGrid, resolveSeriesData } from './plot_grid.js';\n\nexport class PlotPopoutWindow {\n /**\n * @param {Object} options\n * @param {string} options.id - Unique window identifier\n * @param {string} options.title - Window title\n * @param {Object} options.plotConfig - PlotCell format: { layout, subplots }\n * @param {Function} options.getResults - Returns { time: number[], series: { [key]: number[] } }\n * @param {Object} options.services - { eventBus, logger }\n * @param {Object} [options.host] - A Host (ui/js/host/host.js). Its `dialogs`\n * capability backs Export PNG/CSV; absent => Blob download fallback.\n * @param {Function} [options.onClose] - Called when window closes\n * @param {Object} [options.actuals] - ETL overlay data { seriesId: { years, values } }\n * @param {Function} [options.configRenderer] - `(container) => { dispose() } | void` \u2014\n * renders the Config tab. What it returns is disposed (`dispose()`) when the\n * window closes, so an editor drawn there (renderPlotConfigEditor) goes with it.\n * @param {Object} [options.seriesTransforms] - `{ [id]: transform }` (series_transforms.js);\n * absent => no derived series are drawn. Each runs as\n * `run(y, params, { series, subplot, results, resolveSeries })` (renderPlotGrid).\n * @param {string} [options.refreshEvent='data:changed'] - Bus event after which the\n * window re-reads `getResults()` and redraws.\n * @param {{delta?: string|null, complete?: string|null}} [options.streamEvents] - Bus\n * events a live data source emits while it runs (`delta`) and when it ends\n * (`complete`); the window redraws on each while live update is on.\n * There are no default names: without `streamEvents` (or with a name\n * left out or given as null) nothing is listened for, and the window\n * updates through `refreshEvent` and explicit calls only.\n * @param {Function} [options.resolveSeries] - `(series, results, subplot) => { y, x? } | null`\n * (plot_grid.js); used by the chart and the data table. Default resolveSeriesData.\n */\n constructor({ id, title, plotConfig, getResults, services, host, onClose, actuals,\n configRenderer, seriesTransforms, resolveSeries = resolveSeriesData,\n // The window used to listen for 'simulation:run:completed' and tell\n // the user to \"run simulation first\". A chart window does not know\n // that its data comes from a simulation; the app that opens it does.\n refreshEvent = 'data:changed',\n streamEvents = {},\n emptyMessage = 'No data yet.',\n tableEmptyMessage = 'No data yet.' }) {\n this._id = id;\n this._title = title || 'Plot';\n this._plotConfig = migrateData(plotConfig);\n this._getResults = getResults;\n this._services = services;\n this._host = host || null;\n this._onClose = onClose ?? (() => {});\n this._actuals = actuals ?? null;\n this._configRenderer = configRenderer ?? null;\n this._seriesTransforms = seriesTransforms ?? null;\n this._resolveSeries = resolveSeries;\n this.refreshEvent = refreshEvent;\n this.streamEvents = Object.freeze({ delta: streamEvents?.delta ?? null,\n complete: streamEvents?.complete ?? null });\n // TWO messages, not one. The chart says \"No data \u2014 run simulation first.\"\n // and the data table underneath says \"Run simulation to see data\". Folding\n // them into a single option would have quietly rewritten one of them, which\n // is the kind of change a pixel gate catches only if a captured view happens\n // to be showing an empty plot.\n this.emptyMessage = emptyMessage;\n this.tableEmptyMessage = tableEmptyMessage;\n\n this._window = null;\n this._contentEl = null;\n this._grid = null;\n this._gridEl = null;\n this._activeTab = 'plot';\n this._eventDisposers = [];\n this._lastResults = null;\n\n // Data table\n this._dataTable = null;\n this._dataTableContainer = null;\n this._tableHeaders = [];\n this._tableRows = [];\n\n // DOM refs\n this._plotTab = null;\n this._dataTab = null;\n this._configTab = null;\n this._plotContent = null;\n this._dataContent = null;\n this._configContent = null;\n this._configHandle = null;\n this._toolbarActions = null;\n this._zoomBtn = null;\n this._panBtn = null;\n\n // Series visibility toggle\n this._hiddenSeries = new Set();\n this._allSeriesInfo = [];\n this._allSeriesLabels = [];\n this._seriesToggleBtn = null;\n this._seriesTogglePanel = null;\n this._seriesTogglePanelVisible = false;\n this._lastTogglePanelSignature = null;\n this._outsideClickHandler = null;\n\n this._renderPending = false;\n /** updateConfig() ran since the last #render(); applied even without results. */\n this._configChanged = false;\n\n // Live-update toggle: when true, window re-renders on streaming events\n this._liveUpdate = true;\n this._liveBtn = null;\n }\n\n get isVisible() { return this._window?.isVisible ?? false; }\n\n async show() {\n if (this._window?.isVisible) {\n this._window.bringToFront();\n return;\n }\n\n await ensurePlotly();\n this.#createWindow();\n this.#subscribeEvents();\n await this.#render();\n }\n\n bringToFront() { this._window?.bringToFront?.(); }\n\n close() { this._window?.close?.(); }\n\n /** Update plot config and re-render. */\n updateConfig(plotConfig) {\n this._plotConfig = migrateData(plotConfig);\n this._configChanged = true;\n this.#scheduleRender();\n }\n\n /** Update actuals overlay data and re-render. */\n setActuals(actuals) {\n this._actuals = actuals;\n this.#scheduleRender();\n }\n\n // \u2500\u2500 Window creation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n #createWindow() {\n this._contentEl = this.#buildContent();\n\n this._window = new ManagedWindow({\n id: `plot-window-${this._id}`,\n title: this._title,\n icon: 'monitoring',\n content: this._contentEl,\n minWidth: 500,\n minHeight: 400,\n defaultWidth: 800,\n defaultHeight: 600,\n canMinimize: true,\n canMaximize: true,\n canResize: true,\n canDrag: true,\n onClose: () => { this.#dispose(); this._onClose(); },\n });\n\n this._window.show();\n }\n\n #buildContent() {\n const container = document.createElement('div');\n container.className = 'twm-plot-window-container';\n\n // Tab header\n const tabHeader = document.createElement('div');\n tabHeader.className = 'twm-code-tabs-header';\n\n const tabs = document.createElement('div');\n tabs.className = 'tabs twm-code-tabs';\n\n this._plotTab = document.createElement('button');\n this._plotTab.className = 'twm-code-tab active';\n this._plotTab.type = 'button';\n this._plotTab.textContent = 'Plot';\n this._plotTab.addEventListener('click', () => this.#switchTab('plot'));\n\n this._dataTab = document.createElement('button');\n this._dataTab.className = 'twm-code-tab';\n this._dataTab.type = 'button';\n this._dataTab.textContent = 'Data';\n this._dataTab.addEventListener('click', () => this.#switchTab('data'));\n\n tabs.appendChild(this._plotTab);\n tabs.appendChild(this._dataTab);\n\n if (this._configRenderer) {\n this._configTab = document.createElement('button');\n this._configTab.className = 'twm-code-tab';\n this._configTab.type = 'button';\n this._configTab.textContent = 'Config';\n this._configTab.addEventListener('click', () => this.#switchTab('config'));\n tabs.appendChild(this._configTab);\n }\n\n // Toolbar (visible when Plot tab is active)\n this._toolbarActions = document.createElement('div');\n this._toolbarActions.className = 'twm-plot-window-toolbar';\n\n // Drag mode group\n const dragGroup = this.#toolbarGroup();\n this._zoomBtn = this.#toolbarBtn('search', 'Zoom', () => this.#setDragMode('zoom'));\n this._zoomBtn.classList.add('twm-is-active');\n this._panBtn = this.#toolbarBtn('pan_tool', 'Pan', () => this.#setDragMode('pan'));\n dragGroup.appendChild(this._zoomBtn);\n dragGroup.appendChild(this._panBtn);\n this._toolbarActions.appendChild(dragGroup);\n\n // Zoom control group\n const zoomGroup = this.#toolbarGroup();\n zoomGroup.appendChild(this.#toolbarBtn('zoom_in', 'Zoom in', () => this.#zoom(0.5)));\n zoomGroup.appendChild(this.#toolbarBtn('zoom_out', 'Zoom out', () => this.#zoom(2)));\n zoomGroup.appendChild(this.#toolbarBtn('zoom_out_map', 'Autoscale', () => this.#autoscale()));\n zoomGroup.appendChild(this.#toolbarBtn('home', 'Reset axes', () => this.#autoscale()));\n this._toolbarActions.appendChild(zoomGroup);\n\n // Spacer\n const spacer = document.createElement('div');\n spacer.style.flex = '1';\n this._toolbarActions.appendChild(spacer);\n\n // Action buttons group\n const actionsGroup = this.#toolbarGroup();\n\n // Live-update toggle\n this._liveBtn = this.#toolbarBtn('stream', 'Live update \u2014 click to lock', () => this.#toggleLiveUpdate());\n this._liveBtn.classList.add('twm-is-active');\n actionsGroup.appendChild(this._liveBtn);\n\n // Series visibility toggle\n const toggleSeriesBtn = this.#toolbarBtn('visibility', 'Toggle series visibility', () => this.#toggleSeriesPanel());\n this._seriesToggleBtn = toggleSeriesBtn;\n actionsGroup.appendChild(toggleSeriesBtn);\n\n // Download PNG\n actionsGroup.appendChild(this.#toolbarBtn('image', 'Download plot as PNG', () => this.#downloadPNG()));\n\n // Download CSV\n actionsGroup.appendChild(this.#toolbarBtn('download', 'Download data as CSV', () => this.#downloadCSV()));\n\n this._toolbarActions.appendChild(actionsGroup);\n\n tabHeader.appendChild(tabs);\n tabHeader.appendChild(this._toolbarActions);\n\n // Tab content area\n const content = document.createElement('div');\n content.className = 'twm-plot-window-content';\n\n // Plot tab content\n this._plotContent = document.createElement('div');\n this._plotContent.className = 'twm-plot-tab-content active';\n this._plotContent.setAttribute('data-tab', 'plot');\n this._plotContent.style.cssText = 'display:flex; flex-direction:column;';\n\n this._gridEl = document.createElement('div');\n this._gridEl.className = 'twm-plot-window-chart';\n this._plotContent.appendChild(this._gridEl);\n\n this._grid = renderPlotGrid(this._gridEl, this._plotConfig, null, {\n resolveSeries: this._resolveSeries,\n overlays: this._actuals,\n hiddenSeries: this._hiddenSeries,\n seriesTransforms: this._seriesTransforms,\n onTransformError: ({ transformId, traceName, error }) => this._services?.logger?.warn?.(\n `[PlotPopoutWindow] transform \"${transformId}\" failed on \"${traceName}\"`, error),\n // Popout windows have space \u2014 always show the legend.\n alwaysShowLegend: true,\n layout: { autosize: true, hovermode: 'x unified' },\n emptyMessage: this.emptyMessage,\n onError: ({ index, error }) => this._services?.logger?.warn?.(\n `[PlotPopoutWindow] subplot ${index + 1} failed to draw`, error),\n });\n\n // Data tab content\n this._dataContent = document.createElement('div');\n this._dataContent.className = 'twm-plot-tab-content';\n this._dataContent.setAttribute('data-tab', 'data');\n this._dataContent.style.cssText = 'display:none; flex-direction:column;';\n\n this._dataTableContainer = document.createElement('div');\n this._dataTableContainer.style.cssText = 'flex:1; min-height:0; display:flex; flex-direction:column;';\n this._dataContent.appendChild(this._dataTableContainer);\n\n content.appendChild(this._plotContent);\n content.appendChild(this._dataContent);\n\n // Config tab content (optional)\n if (this._configRenderer) {\n this._configContent = document.createElement('div');\n this._configContent.className = 'twm-plot-tab-content';\n this._configContent.setAttribute('data-tab', 'config');\n this._configContent.style.cssText = 'display:none; flex-direction:column; overflow:auto; padding:8px 12px;';\n this._configHandle = this._configRenderer(this._configContent) ?? null;\n content.appendChild(this._configContent);\n }\n\n // Series visibility dropdown panel (initially hidden)\n this._seriesTogglePanel = document.createElement('div');\n this._seriesTogglePanel.className = 'twm-plot-series-toggle-panel';\n this._seriesTogglePanel.style.display = 'none';\n\n container.appendChild(tabHeader);\n container.appendChild(content);\n container.appendChild(this._seriesTogglePanel);\n\n return container;\n }\n\n // \u2500\u2500 Toolbar helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n #toolbarGroup() {\n const g = document.createElement('div');\n g.className = 'twm-plot-window-toolbar__group';\n return g;\n }\n\n #toolbarBtn(icon, tooltip, onClick) {\n const btn = document.createElement('button');\n btn.className = 'twm-btn-icon twm-has-tooltip';\n btn.type = 'button';\n btn.setAttribute('data-tooltip', tooltip);\n btn.innerHTML = `<span class=\"material-symbols-outlined\">${icon}</span>`;\n if (onClick) btn.addEventListener('click', (e) => { e.stopPropagation(); onClick(); });\n return btn;\n }\n\n // \u2500\u2500 Plotly toolbar actions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n get #charts() { return this._grid?.charts ?? []; }\n /** The subplots that show a figure \u2014 the grid knows, however it drew them. */\n get #plottedCharts() { return this._grid?.plotted ?? []; }\n\n #setDragMode(mode) {\n if (!this.#plottedCharts.length) return;\n for (const div of this.#charts) {\n if (div._fullLayout) {\n window.Plotly.relayout(div, { dragmode: mode }).catch(() => {});\n }\n }\n this._zoomBtn?.classList.toggle('twm-is-active', mode === 'zoom');\n this._panBtn?.classList.toggle('twm-is-active', mode === 'pan');\n }\n\n #zoom(factor) {\n for (const div of this.#charts) {\n if (!div._fullLayout) continue;\n const xa = div._fullLayout.xaxis;\n const ya = div._fullLayout.yaxis;\n if (!xa || !ya) continue;\n\n const xr = xa.range;\n const yr = ya.range;\n const xMid = (xr[0] + xr[1]) / 2;\n const yMid = (yr[0] + yr[1]) / 2;\n const xHalf = (xr[1] - xr[0]) / 2 * factor;\n const yHalf = (yr[1] - yr[0]) / 2 * factor;\n\n window.Plotly.relayout(div, {\n 'xaxis.range': [xMid - xHalf, xMid + xHalf],\n 'yaxis.range': [yMid - yHalf, yMid + yHalf],\n }).catch(() => {});\n }\n }\n\n #autoscale() {\n for (const div of this.#charts) {\n if (!div._fullLayout) continue;\n window.Plotly.relayout(div, {\n 'xaxis.autorange': true,\n 'yaxis.autorange': true,\n }).catch(() => {});\n }\n }\n\n #switchTab(tabName) {\n this._activeTab = tabName;\n\n this._plotTab.classList.toggle('active', tabName === 'plot');\n this._dataTab.classList.toggle('active', tabName === 'data');\n this._configTab?.classList.toggle('active', tabName === 'config');\n\n if (this._toolbarActions) {\n this._toolbarActions.style.display = tabName === 'plot' ? '' : 'none';\n }\n\n this._plotContent.style.display = tabName === 'plot' ? 'flex' : 'none';\n this._dataContent.style.display = tabName === 'data' ? 'flex' : 'none';\n if (this._configContent) {\n this._configContent.style.display = tabName === 'config' ? 'flex' : 'none';\n }\n\n if (tabName === 'plot') this._grid?.resize();\n\n if (tabName === 'data') {\n this.#renderDataTable();\n }\n }\n\n // \u2500\u2500 Series visibility toggle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n #toggleSeriesPanel() {\n if (this._seriesTogglePanelVisible) {\n this.#hideSeriesPanel();\n } else {\n this.#showSeriesPanel();\n }\n }\n\n #showSeriesPanel() {\n if (!this._seriesTogglePanel || !this._seriesToggleBtn) return;\n\n const btnRect = this._seriesToggleBtn.getBoundingClientRect();\n const containerRect = this._contentEl.getBoundingClientRect();\n\n this._seriesTogglePanel.style.top = `${btnRect.bottom - containerRect.top + 4}px`;\n this._seriesTogglePanel.style.right = `${containerRect.right - btnRect.right}px`;\n this._seriesTogglePanel.style.display = '';\n this._seriesTogglePanelVisible = true;\n\n this._seriesToggleBtn.classList.add('twm-is-active');\n this.#rebuildSeriesToggleList();\n\n this._outsideClickHandler = (e) => {\n if (!this._seriesTogglePanel.contains(e.target) &&\n !this._seriesToggleBtn.contains(e.target)) {\n this.#hideSeriesPanel();\n }\n };\n requestAnimationFrame(() => {\n document.addEventListener('pointerdown', this._outsideClickHandler, true);\n });\n }\n\n #hideSeriesPanel() {\n if (this._seriesTogglePanel) {\n this._seriesTogglePanel.style.display = 'none';\n }\n this._seriesTogglePanelVisible = false;\n this._lastTogglePanelSignature = null;\n this._seriesToggleBtn?.classList.remove('twm-is-active');\n\n if (this._outsideClickHandler) {\n document.removeEventListener('pointerdown', this._outsideClickHandler, true);\n this._outsideClickHandler = null;\n }\n }\n\n #rebuildSeriesToggleList() {\n const panel = this._seriesTogglePanel;\n if (!panel) return;\n panel.innerHTML = '';\n\n // Header with \"All\" / \"None\" actions\n const header = document.createElement('div');\n header.className = 'twm-plot-series-toggle-panel__header';\n\n const title = document.createElement('span');\n title.className = 'twm-plot-series-toggle-panel__title';\n title.textContent = 'Series';\n header.appendChild(title);\n\n const headerActions = document.createElement('div');\n headerActions.className = 'twm-plot-series-toggle-panel__header-actions';\n\n const showAllBtn = document.createElement('button');\n showAllBtn.className = 'twm-plot-series-toggle-panel__action';\n showAllBtn.type = 'button';\n showAllBtn.textContent = 'All';\n showAllBtn.addEventListener('click', () => {\n this._hiddenSeries.clear();\n this.#rebuildSeriesToggleList();\n this.#scheduleRender();\n });\n\n const hideAllBtn = document.createElement('button');\n hideAllBtn.className = 'twm-plot-series-toggle-panel__action';\n hideAllBtn.type = 'button';\n hideAllBtn.textContent = 'None';\n hideAllBtn.addEventListener('click', () => {\n for (const label of this._allSeriesLabels) {\n this._hiddenSeries.add(label);\n }\n this.#rebuildSeriesToggleList();\n this.#scheduleRender();\n });\n\n headerActions.appendChild(showAllBtn);\n headerActions.appendChild(hideAllBtn);\n header.appendChild(headerActions);\n panel.appendChild(header);\n\n // Split series into model vs overlay\n const modelSeries = this._allSeriesInfo.filter(s => !s.isOverlay);\n const overlaySeries = this._allSeriesInfo.filter(s => s.isOverlay);\n\n const buildItem = ({ label, color, lineStyle }) => {\n const item = document.createElement('label');\n item.className = 'twm-plot-series-toggle-panel__item';\n\n const cb = document.createElement('input');\n cb.type = 'checkbox';\n cb.checked = !this._hiddenSeries.has(label);\n cb.addEventListener('change', () => {\n if (cb.checked) this._hiddenSeries.delete(label);\n else this._hiddenSeries.add(label);\n this.#scheduleRender();\n });\n\n const dashMap = { solid: '', dashed: '4,2', dotted: '1,2' };\n const indicator = document.createElement('div');\n indicator.className = 'twm-plot-series-toggle-panel__line-indicator';\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.setAttribute('viewBox', '0 0 28 14');\n const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');\n line.setAttribute('x1', '3');\n line.setAttribute('y1', '7');\n line.setAttribute('x2', '25');\n line.setAttribute('y2', '7');\n line.setAttribute('stroke', color || '#888');\n line.setAttribute('stroke-width', '2');\n line.setAttribute('stroke-linecap', 'round');\n const dash = dashMap[lineStyle] || '';\n if (dash) line.setAttribute('stroke-dasharray', dash);\n svg.appendChild(line);\n indicator.appendChild(svg);\n\n const text = document.createElement('span');\n text.className = 'twm-plot-series-toggle-panel__label';\n text.textContent = label;\n text.title = label;\n\n item.appendChild(cb);\n item.appendChild(indicator);\n item.appendChild(text);\n return item;\n };\n\n // Model series section\n const list = document.createElement('div');\n list.className = 'twm-plot-series-toggle-panel__list';\n\n const subplotGroups = new Map();\n for (const info of modelSeries) {\n if (!subplotGroups.has(info.subplotIndex)) {\n subplotGroups.set(info.subplotIndex, []);\n }\n subplotGroups.get(info.subplotIndex).push(info);\n }\n\n const multipleSubplots = subplotGroups.size > 1;\n\n for (const [spIdx, seriesList] of subplotGroups) {\n if (multipleSubplots) {\n const spName = seriesList[0]?.subplotName || `Subplot ${spIdx + 1}`;\n const spHeader = document.createElement('div');\n spHeader.className = 'twm-plot-series-toggle-panel__axis-label';\n spHeader.textContent = spName;\n list.appendChild(spHeader);\n }\n\n for (const info of seriesList) {\n list.appendChild(buildItem(info));\n }\n }\n\n panel.appendChild(list);\n\n // Overlays section (only if any exist)\n if (overlaySeries.length > 0) {\n const ovList = document.createElement('div');\n ovList.className = 'twm-plot-series-toggle-panel__list';\n\n const ovHeader = document.createElement('div');\n ovHeader.className = 'twm-plot-series-toggle-panel__axis-label';\n ovHeader.textContent = 'Overlays';\n ovList.appendChild(ovHeader);\n\n for (const info of overlaySeries) {\n ovList.appendChild(buildItem(info));\n }\n\n panel.appendChild(ovList);\n }\n }\n\n // \u2500\u2500 Event subscriptions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n #subscribeEvents() {\n const { eventBus } = this._services;\n if (!eventBus) return;\n\n const { delta, complete } = this.streamEvents;\n for (const name of new Set([delta, complete])) {\n if (!name) continue;\n this._eventDisposers.push(\n eventBus.on(name, () => {\n if (this._liveUpdate) this.#scheduleRender();\n })\n );\n }\n // Final analytics arrive asynchronously after the stream's complete event\n // (backend fetch + transform). Without this, the popout window may\n // render stale data from a previous run when the dashboard tab\n // didn't receive streaming deltas (e.g. user was on another tab).\n this._eventDisposers.push(\n eventBus.on(this.refreshEvent, () => {\n if (this._liveUpdate) this.#scheduleRender();\n })\n );\n }\n\n #toggleLiveUpdate() {\n this._liveUpdate = !this._liveUpdate;\n if (this._liveBtn) {\n this._liveBtn.classList.toggle('twm-is-active', this._liveUpdate);\n const icon = this._liveBtn.querySelector('.material-symbols-outlined');\n if (icon) icon.textContent = this._liveUpdate ? 'stream' : 'lock';\n this._liveBtn.title = this._liveUpdate\n ? 'Live update \u2014 click to lock'\n : 'Locked \u2014 click for live update';\n }\n // If switching back to live, immediately render latest data\n if (this._liveUpdate) this.#scheduleRender();\n }\n\n #scheduleRender() {\n if (this._renderPending) return;\n this._renderPending = true;\n requestAnimationFrame(() => {\n this._renderPending = false;\n this.#render();\n });\n }\n\n // \u2500\u2500 Rendering \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async #render() {\n if (!this._window?.isVisible) return;\n\n const results = this._getResults?.();\n const configChanged = this._configChanged;\n this._configChanged = false;\n if (!results) {\n // No data yet: the figures already drawn stay, unless the layout or\n // the subplots changed, in which case the grid is rebuilt for them.\n if (configChanged) {\n await this._grid.update({\n plotConfig: this._plotConfig,\n results: null,\n overlays: this._actuals,\n hiddenSeries: this._hiddenSeries,\n });\n }\n return;\n }\n\n this._lastResults = results;\n\n // Build series info for toggle panel\n this.#collectSeriesInfo();\n\n // Render all subplot charts\n await this._grid.update({\n plotConfig: this._plotConfig,\n results,\n overlays: this._actuals,\n hiddenSeries: this._hiddenSeries,\n });\n if (!this._window) return;\n\n // Update table data\n this.#updateTableData(results);\n\n if (this._activeTab === 'data') {\n this.#renderDataTable();\n }\n }\n\n #collectSeriesInfo() {\n this._allSeriesInfo = [];\n this._allSeriesLabels = [];\n\n const subplots = this._plotConfig.subplots ?? [];\n for (let spIdx = 0; spIdx < subplots.length; spIdx++) {\n const sp = subplots[spIdx];\n for (const axis of sp.yAxes ?? []) {\n for (const s of axis.series ?? []) {\n const label = s.label || s.variable || 'Series';\n this._allSeriesInfo.push({\n label,\n color: s.color || getSeriesColor(this._allSeriesInfo.length),\n lineStyle: s.lineStyle || 'solid',\n subplotIndex: spIdx,\n subplotName: sp.displayName || `Subplot ${spIdx + 1}`,\n });\n this._allSeriesLabels.push(label);\n\n // Include overlay in toggle list\n if (s.overlay) {\n const ovLabel = s.overlay.label || `${label} (actual)`;\n this._allSeriesInfo.push({\n label: ovLabel,\n color: s.overlay.color || s.color || getSeriesColor(this._allSeriesInfo.length),\n lineStyle: s.overlay.lineStyle || 'dashed',\n subplotIndex: spIdx,\n subplotName: sp.displayName || `Subplot ${spIdx + 1}`,\n isOverlay: true,\n });\n this._allSeriesLabels.push(ovLabel);\n }\n }\n }\n }\n\n // Prune hidden labels that no longer exist\n for (const label of this._hiddenSeries) {\n if (!this._allSeriesLabels.includes(label)) {\n this._hiddenSeries.delete(label);\n }\n }\n\n // Update toggle panel if visible\n if (this._seriesTogglePanelVisible) {\n const newSig = this._allSeriesInfo.map(s => `${s.subplotIndex}|${s.label}|${s.lineStyle}`).join('\\x00');\n if (newSig !== this._lastTogglePanelSignature) {\n this._lastTogglePanelSignature = newSig;\n this.#rebuildSeriesToggleList();\n }\n }\n\n // Update toggle button icon\n if (this._seriesToggleBtn) {\n const icon = this._seriesToggleBtn.querySelector('.material-symbols-outlined');\n if (icon) {\n icon.textContent = this._hiddenSeries.size > 0 ? 'visibility_off' : 'visibility';\n }\n }\n }\n\n // \u2500\u2500 Data table \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n #updateTableData(results) {\n if (!results) {\n this._tableHeaders = [];\n this._tableRows = [];\n return;\n }\n\n const headers = ['Time'];\n const seriesColumns = [];\n const { time } = results;\n const subplots = this._plotConfig.subplots ?? [];\n\n for (const sp of subplots) {\n for (const axis of sp.yAxes ?? []) {\n for (const s of axis.series ?? []) {\n if (!s.variable) continue;\n const label = s.label || s.variable;\n const rawY = this._resolveSeries(s, results, sp)?.y;\n if (!rawY) continue;\n headers.push(label);\n seriesColumns.push(rawY);\n }\n }\n }\n\n const rows = [];\n for (let i = 0; i < time.length; i++) {\n const row = [time[i]];\n for (const col of seriesColumns) {\n row.push(Array.isArray(col) ? col[i] : null);\n }\n rows.push(row);\n }\n\n this._tableHeaders = headers;\n this._tableRows = rows;\n }\n\n #renderDataTable() {\n if (!this._dataTableContainer) return;\n\n if (!this._dataTable) {\n this._dataTable = new DataTable(this._dataTableContainer, {\n headers: this._tableHeaders,\n rows: this._tableRows,\n pageSize: 100,\n pagination: true,\n selectable: true,\n copyable: true,\n sortable: true,\n filterable: true,\n readonly: false,\n emptyMessage: this.tableEmptyMessage,\n services: this._services,\n host: this._host,\n });\n this._dataTable.render();\n } else {\n this._dataTable.setData({\n headers: this._tableHeaders,\n rows: this._tableRows,\n });\n }\n }\n\n // \u2500\u2500 Downloads \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async #downloadCSV() {\n if (this._tableRows.length === 0) {\n this.#notify('Download', 'No data available to download.', 'warn');\n return;\n }\n\n const filename = `${this._title.replace(/[^a-z0-9]/gi, '_')}_data.csv`;\n\n const lines = [this._tableHeaders.join(',')];\n for (const row of this._tableRows) {\n lines.push(row.map(val => this.#csvEscape(val)).join(','));\n }\n const csv = lines.join('\\n');\n\n // null <=> the host has no save dialog behind its `dialogs` capability\n // (host.js). Fall back; do not report it as a failed save.\n const dialogs = this._host?.dialogs;\n let result = null;\n if (dialogs) {\n try {\n result = await dialogs.saveFile({ data: csv, filename, kind: 'csv' });\n } catch (err) {\n console.error('[PlotPopoutWindow] CSV download failed:', err);\n this.#notify('Download', 'Failed to save file', 'error');\n return;\n }\n }\n if (result) {\n if (result.ok) {\n this.#notify('Download', `Saved ${this._tableRows.length} rows to ${result.path}`, 'success');\n } else if (!result.cancelled) {\n this.#notify('Download', result.error || 'Failed to save file', 'error');\n }\n return;\n }\n\n const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n link.click();\n URL.revokeObjectURL(url);\n this.#notify('Download', 'Download started', 'info');\n }\n\n #csvEscape(value) {\n if (value == null) return '';\n const str = String(value);\n if (str.includes(',') || str.includes('\"') || str.includes('\\n')) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`;\n }\n return str;\n }\n\n async #downloadPNG() {\n // The first subplot that shows a figure.\n const targetDiv = this.#plottedCharts[0];\n if (!targetDiv || !window.Plotly) {\n this.#notify('Download', 'Plot not ready', 'warn');\n return;\n }\n\n const filename = `${this._title.replace(/[^a-z0-9]/gi, '_')}.png`;\n\n try {\n const pngDataUrl = await window.Plotly.toImage(targetDiv, {\n format: 'png',\n width: 1920,\n height: 1080,\n scale: 2,\n });\n\n // null <=> no save dialog behind the capability (host.js) -> fall back.\n const dialogs = this._host?.dialogs;\n const result = dialogs\n ? await dialogs.saveFile({ data: pngDataUrl.split(',')[1], filename, kind: 'png' })\n : null;\n if (result) {\n if (result.ok) {\n this.#notify('Download', `Plot saved to ${result.path}`, 'success');\n } else if (!result.cancelled) {\n this.#notify('Download', result.error || 'Failed to save image', 'error');\n }\n } else {\n const link = document.createElement('a');\n link.href = pngDataUrl;\n link.download = filename;\n link.click();\n this.#notify('Download', 'PNG download started', 'info');\n }\n } catch (err) {\n this._services.logger?.warn?.('[PlotPopoutWindow] PNG download failed', err);\n this.#notify('Download', 'Failed to generate PNG', 'error');\n }\n }\n\n // \u2500\u2500 Utilities \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n #notify(title, message, severity = 'info') {\n this._services.eventBus?.emit?.('toast:show', {\n title,\n message,\n type: severity,\n });\n }\n\n // \u2500\u2500 Cleanup \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n #dispose() {\n if (this._dataTable) {\n this._dataTable.dispose();\n this._dataTable = null;\n }\n\n this.#hideSeriesPanel();\n\n for (const disposer of this._eventDisposers) {\n try { disposer?.dispose?.(); } catch (_) {}\n }\n this._eventDisposers = [];\n\n // What configRenderer returned (an editor with dropdowns in document.body,\n // say) goes with the window.\n try { this._configHandle?.dispose?.(); } catch (error) {\n this._services?.logger?.warn?.('[PlotPopoutWindow] the config panel failed to dispose', error);\n }\n this._configHandle = null;\n\n this._grid?.dispose();\n this._grid = null;\n\n this._window = null;\n this._contentEl = null;\n this._gridEl = null;\n this._plotTab = null;\n this._dataTab = null;\n this._plotContent = null;\n this._dataContent = null;\n this._dataTableContainer = null;\n this._toolbarActions = null;\n this._zoomBtn = null;\n this._panBtn = null;\n this._seriesToggleBtn = null;\n this._seriesTogglePanel = null;\n this._lastTogglePanelSignature = null;\n this._hiddenSeries = null;\n this._allSeriesInfo = null;\n this._allSeriesLabels = null;\n this._lastResults = null;\n }\n}\n\n// \u2500\u2500 Singleton window manager \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst _openWindows = new Map();\n\n/**\n * Open or focus a plot popout window.\n *\n * @param {Object} options\n * @param {string} options.id - Unique window identifier\n * @param {string} options.title - Window title\n * @param {Object} options.plotConfig - PlotCell format: { layout, subplots }\n * @param {Function} options.getResults - Returns { time: number[], series: { [key]: number[] } }\n * @param {Object} options.services - { eventBus, logger }\n * @param {Object} [options.actuals] - ETL overlay data\n * @returns {PlotPopoutWindow}\n */\nexport async function openPlotPopoutWindow(options) {\n const { id } = options;\n let win = _openWindows.get(id);\n if (win?.isVisible) {\n win.bringToFront();\n return win;\n }\n\n // Forward the WHOLE options object. This used to destructure a fixed list of\n // eight names and rebuild the object from them, which means every option added\n // to the constructor from now on would be silently dropped on its way through\n // the factory \u2014 including `refreshEvent`, whose loss would show up as a plot\n // window that simply stops updating, with no error anywhere.\n win = new PlotPopoutWindow({\n ...options,\n onClose: () => _openWindows.delete(id),\n });\n _openWindows.set(id, win);\n\n await win.show();\n return win;\n}\n\n// \u2500\u2500 Raw-traces window (for dashboard tile expand) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Open a ManagedWindow with pre-built Plotly traces.\n *\n * Reuses the same toolbar, tab layout, and download logic as PlotPopoutWindow\n * but accepts ready-made `{ traces, layout }` instead of plotConfig + getResults.\n * Used by dashboard tile widgets whose getExpandData() returns raw Plotly specs.\n *\n * @param {Object} options\n * @param {string} options.id - Unique window identifier\n * @param {string} options.title - Window title\n * @param {Array} options.traces - Plotly trace objects\n * @param {Object} options.layout - Plotly layout object\n * @param {Array} [options.tableHeaders] - Column headers for Data tab\n * @param {Array} [options.tableRows] - Row data for Data tab\n * @param {Object} [options.services] - { eventBus, logger }\n * @param {Object} [options.host] - A Host (ui/js/host/host.js); backs Export PNG/CSV.\n * @returns {{ close: Function, bringToFront: Function }}\n */\nexport async function openRawTracesWindow({ id, title, traces, layout, frames, tableHeaders, tableRows, services, host }) {\n const existing = _openWindows.get(id);\n if (existing?.isVisible) {\n existing.bringToFront();\n return existing;\n }\n\n await ensurePlotly();\n\n // State\n let chartDiv = null;\n let chartCreated = false;\n let resizeObserver = null;\n let dataTable = null;\n let managedWindow = null;\n\n // \u2500\u2500 Build content DOM \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const container = document.createElement('div');\n container.className = 'twm-plot-window-container';\n\n // Tab header\n const tabHeader = document.createElement('div');\n tabHeader.className = 'twm-code-tabs-header';\n\n const tabs = document.createElement('div');\n tabs.className = 'tabs twm-code-tabs';\n\n const plotTab = document.createElement('button');\n plotTab.className = 'twm-code-tab active';\n plotTab.type = 'button';\n plotTab.textContent = 'Plot';\n\n const dataTab = document.createElement('button');\n dataTab.className = 'twm-code-tab';\n dataTab.type = 'button';\n dataTab.textContent = 'Data';\n\n tabs.appendChild(plotTab);\n tabs.appendChild(dataTab);\n\n // Toolbar (same layout as PlotPopoutWindow)\n const toolbar = document.createElement('div');\n toolbar.className = 'twm-plot-window-toolbar';\n\n const spacer = document.createElement('div');\n spacer.style.flex = '1';\n toolbar.appendChild(spacer);\n\n const actionsGroup = document.createElement('div');\n actionsGroup.className = 'twm-plot-window-toolbar__group';\n\n const mkBtn = (icon, tooltip, onClick) => {\n const btn = document.createElement('button');\n btn.className = 'twm-btn-icon twm-has-tooltip';\n btn.type = 'button';\n btn.setAttribute('data-tooltip', tooltip);\n btn.innerHTML = `<span class=\"material-symbols-outlined\">${icon}</span>`;\n btn.addEventListener('click', (e) => { e.stopPropagation(); onClick(); });\n return btn;\n };\n\n actionsGroup.appendChild(mkBtn('image', 'Download plot as PNG', downloadPNG));\n actionsGroup.appendChild(mkBtn('download', 'Download data as CSV', downloadCSV));\n toolbar.appendChild(actionsGroup);\n\n tabHeader.appendChild(tabs);\n tabHeader.appendChild(toolbar);\n\n // Tab content\n const content = document.createElement('div');\n content.className = 'twm-plot-window-content';\n\n const plotContent = document.createElement('div');\n plotContent.className = 'twm-plot-tab-content active';\n plotContent.setAttribute('data-tab', 'plot');\n plotContent.style.cssText = 'display:flex; flex-direction:column;';\n\n chartDiv = document.createElement('div');\n chartDiv.className = 'twm-plot-window-chart';\n plotContent.appendChild(chartDiv);\n\n const dataContent = document.createElement('div');\n dataContent.className = 'twm-plot-tab-content';\n dataContent.setAttribute('data-tab', 'data');\n dataContent.style.cssText = 'display:none; flex-direction:column;';\n\n const dataTableContainer = document.createElement('div');\n dataTableContainer.style.cssText = 'flex:1; min-height:0; display:flex; flex-direction:column;';\n dataContent.appendChild(dataTableContainer);\n\n content.appendChild(plotContent);\n content.appendChild(dataContent);\n\n container.appendChild(tabHeader);\n container.appendChild(content);\n\n // Tab switching\n plotTab.addEventListener('click', () => {\n plotTab.classList.add('active');\n dataTab.classList.remove('active');\n toolbar.style.display = '';\n plotContent.style.display = 'flex';\n dataContent.style.display = 'none';\n if (chartCreated && window.Plotly && chartDiv) {\n try { window.Plotly.Plots.resize(chartDiv); } catch (_) {}\n }\n });\n\n dataTab.addEventListener('click', () => {\n dataTab.classList.add('active');\n plotTab.classList.remove('active');\n toolbar.style.display = 'none';\n plotContent.style.display = 'none';\n dataContent.style.display = 'flex';\n if (!dataTable && tableHeaders?.length) {\n dataTable = new DataTable(dataTableContainer, {\n headers: tableHeaders,\n rows: tableRows || [],\n pagination: true,\n pageSize: 100,\n selectable: true,\n copyable: true,\n sortable: true,\n filterable: true,\n readonly: true,\n emptyMessage: 'No data available',\n services,\n host,\n });\n dataTable.render();\n }\n });\n\n // \u2500\u2500 Create window \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n function dispose() {\n if (resizeObserver) { resizeObserver.disconnect(); resizeObserver = null; }\n if (dataTable) { dataTable.dispose(); dataTable = null; }\n if (chartDiv && window.Plotly) { try { purge(chartDiv); } catch (_) {} }\n chartDiv = null;\n chartCreated = false;\n managedWindow = null;\n _openWindows.delete(id);\n }\n\n managedWindow = new ManagedWindow({\n id: `raw-plot-${id}`,\n title: title || 'Chart',\n icon: 'monitoring',\n content: container,\n minWidth: 500,\n minHeight: 400,\n defaultWidth: 800,\n defaultHeight: 600,\n canMinimize: true,\n canMaximize: true,\n canResize: true,\n canDrag: true,\n onClose: dispose,\n });\n\n const handle = {\n get isVisible() { return managedWindow?.isVisible ?? false; },\n bringToFront() { managedWindow?.bringToFront?.(); },\n close() { managedWindow?.close?.(); },\n };\n\n _openWindows.set(id, handle);\n managedWindow.show();\n\n // Render plot\n const defaultMargin = { l: 60, r: 30, t: 40, b: 60 };\n const plotLayout = {\n paper_bgcolor: 'transparent',\n plot_bgcolor: 'transparent',\n font: { family: 'Inter, -apple-system, BlinkMacSystemFont, sans-serif', color: '#cccccc', size: 11 },\n hoverlabel: {\n bgcolor: '#1e2228',\n bordercolor: '#444444',\n font: { family: 'Inter, -apple-system, BlinkMacSystemFont, sans-serif', color: '#cccccc' },\n },\n autosize: true,\n hovermode: 'x unified',\n ...layout,\n margin: { ...defaultMargin, ...(layout?.margin || {}) },\n };\n\n await window.Plotly.newPlot(chartDiv, traces, plotLayout, {\n responsive: true,\n displayModeBar: true,\n displaylogo: false,\n modeBarButtonsToRemove: ['lasso2d', 'select2d', 'toImage'],\n });\n if (Array.isArray(frames) && frames.length) {\n try { await window.Plotly.addFrames(chartDiv, frames); }\n catch (err) { console.warn('[openRawTracesWindow] addFrames failed:', err); }\n }\n chartCreated = true;\n\n // Resize observer\n resizeObserver = createRafResizeObserver(() => {\n if (chartDiv && chartCreated && window.Plotly) {\n try { window.Plotly.Plots.resize(chartDiv); } catch (_) {}\n }\n });\n resizeObserver.observe(plotContent);\n\n // \u2500\u2500 Download helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n function notify(ntitle, message, severity = 'info') {\n services?.eventBus?.emit?.('toast:show', { title: ntitle, message, type: severity });\n }\n\n async function downloadPNG() {\n if (!chartDiv || !chartCreated || !window.Plotly) {\n notify('Download', 'Plot not ready', 'warn');\n return;\n }\n const filename = `${(title || 'chart').replace(/[^a-z0-9]/gi, '_')}.png`;\n try {\n const dataUrl = await window.Plotly.toImage(chartDiv, {\n format: 'png', width: 1920, height: 1080, scale: 2,\n });\n // null <=> no save dialog behind the capability (host.js) -> fall back.\n const dialogs = host?.dialogs;\n const result = dialogs\n ? await dialogs.saveFile({ data: dataUrl.split(',')[1], filename, kind: 'png' })\n : null;\n if (result) {\n if (result.ok) notify('Download', `Plot saved to ${result.path}`, 'success');\n else if (!result.cancelled) notify('Download', result.error || 'Failed to save image', 'error');\n } else {\n const link = document.createElement('a');\n link.href = dataUrl;\n link.download = filename;\n link.click();\n notify('Download', 'PNG download started', 'info');\n }\n } catch (err) {\n console.error('[openRawTracesWindow] PNG download failed:', err);\n notify('Download', 'Failed to generate PNG', 'error');\n }\n }\n\n async function downloadCSV() {\n if (!tableRows?.length) {\n notify('Download', 'No data available to download', 'warn');\n return;\n }\n const filename = `${(title || 'data').replace(/[^a-z0-9]/gi, '_')}_data.csv`;\n const csvEscape = (val) => {\n if (val == null) return '';\n const str = String(val);\n return (str.includes(',') || str.includes('\"') || str.includes('\\n'))\n ? `\"${str.replace(/\"/g, '\"\"')}\"` : str;\n };\n const lines = [(tableHeaders || []).join(',')];\n for (const row of tableRows) lines.push(row.map(csvEscape).join(','));\n const csv = lines.join('\\n');\n\n // null <=> no save dialog behind the capability (host.js) -> fall back.\n const dialogs = host?.dialogs;\n let result = null;\n if (dialogs) {\n try {\n result = await dialogs.saveFile({ data: csv, filename, kind: 'csv' });\n } catch (err) {\n console.error('[openRawTracesWindow] CSV download failed:', err);\n notify('Download', 'Failed to save file', 'error');\n return;\n }\n }\n if (result) {\n if (result.ok) notify('Download', `Saved ${tableRows.length} rows to ${result.path}`, 'success');\n else if (!result.cancelled) notify('Download', result.error || 'Failed to save file', 'error');\n } else {\n const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n link.click();\n URL.revokeObjectURL(url);\n notify('Download', 'Download started', 'info');\n }\n }\n\n return handle;\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["/**\n * Plotly.js Wrapper\n *\n * Provides lazy loading of Plotly.js and helper functions for chart operations.\n * Supports streaming updates via Plotly.extendTraces() and Plotly.react().\n */\n\nimport { createRafResizeObserver } from '../ui/utils/raf_resize_observer.js';\n\n// Where Plotly lives is the CONSUMER's business, not the library's.\n//\n// This was `const PLOTLY_LOCAL = 'vendor/plotly/plotly-2.35.2.min.js'` \u2014 a\n// relative path into one particular application's directory tree. It happens to\n// work for EcoAgent and would 404 for anyone else, and the failure would arrive\n// as an empty chart with a console error, at runtime, only on the screens that\n// plot something.\n//\n// Plotly stays a PEER dependency: 4.4 MB that @flexdesk/charts refuses to bundle.\n//\n// There is NO DEFAULT. Leaving one in place would only have meant leaving\n// EcoAgent's exact versioned filename in the library \u2014 the same bug wearing a\n// setter \u2014 and it would fail for everyone else as an empty chart and a console\n// error, at runtime, on the screens that plot something.\n//\n// ensurePlotly() short-circuits when `window.Plotly` is already defined, which is\n// how EcoAgent works: it preloads Plotly with a <script> tag in index.html and\n// never reaches the loader below. A consumer that does not preload calls\n// setPlotlySource() instead. A consumer that does neither now gets told so.\nlet _plotlySrc = null;\n\n/** Point the loader at your copy of Plotly. Call before the first chart renders. */\nexport function setPlotlySource(src) {\n if (typeof src === 'string' && src) _plotlySrc = src;\n}\n\n// Loading promise for singleton pattern\nlet _plotlyLoadPromise = null;\n\n// Workarounds for Plotly.js 2.35.x running in Chromium-based pywebview.\nlet _plotlyPatchesInstalled = false;\nfunction _installPlotlyPatches() {\n if (_plotlyPatchesInstalled) return;\n _plotlyPatchesInstalled = true;\n\n // Plotly's internal mousemove handler assigns event.target which is\n // read-only in modern browsers. Replace the native getter with a\n // getter/setter pair so the assignment succeeds silently.\n const targetDesc = Object.getOwnPropertyDescriptor(Event.prototype, 'target');\n if (targetDesc && targetDesc.get && !targetDesc.set) {\n const origGetter = targetDesc.get;\n Object.defineProperty(Event.prototype, 'target', {\n configurable: true,\n enumerable: true,\n get() {\n return this._plotlyTarget ?? origGetter.call(this);\n },\n set(v) {\n this._plotlyTarget = v;\n }\n });\n }\n\n // Plotly calls getImageData() repeatedly on 2D canvases without the\n // willReadFrequently hint, triggering a Chromium performance warning.\n // Patch getContext to inject the hint for all 2D contexts.\n const _origGetContext = HTMLCanvasElement.prototype.getContext;\n HTMLCanvasElement.prototype.getContext = function (type, attrs) {\n if (type === '2d') {\n attrs = Object.assign({ willReadFrequently: true }, attrs);\n }\n return _origGetContext.call(this, type, attrs);\n };\n}\n\n// Run immediately on module import so the patches are active before any Plotly\n// chart is created (including during workspace hydration) \u2014 but ONLY in a DOM.\n//\n// Unguarded, this monkey-patched HTMLCanvasElement.prototype at module scope, so\n// `import '@flexdesk/charts'` threw `ReferenceError: HTMLCanvasElement is not defined`\n// the instant anything imported it outside a browser. That is the third module in\n// this library caught doing DOM work on import (see inline_renamer.js and\n// tooltip_service.js), and all three were found by the same test: one that does\n// nothing but import each entry point. A library whose entry point cannot be\n// imported without a DOM cannot be unit-tested, server-rendered, or loaded in a\n// worker.\nif (typeof HTMLCanvasElement !== 'undefined') {\n _installPlotlyPatches();\n}\n\n/**\n * Dark theme layout defaults matching the shell's dark UI\n */\nexport const DARK_THEME_LAYOUT = {\n paper_bgcolor: 'transparent',\n plot_bgcolor: 'transparent',\n font: {\n family: 'Inter, -apple-system, BlinkMacSystemFont, sans-serif',\n size: 11,\n color: '#cccccc'\n },\n margin: { l: 50, r: 20, t: 30, b: 40 },\n legend: {\n bgcolor: 'rgba(0,0,0,0)',\n font: { color: '#cccccc' }\n },\n xaxis: {\n gridcolor: '#333333',\n linecolor: '#444444',\n tickcolor: '#666666',\n zerolinecolor: '#444444'\n },\n yaxis: {\n gridcolor: '#333333',\n linecolor: '#444444',\n tickcolor: '#666666',\n zerolinecolor: '#444444'\n },\n // Hover tooltip styling for dark theme\n hoverlabel: {\n bgcolor: '#1e2228',\n bordercolor: '#444444',\n font: {\n family: 'Inter, -apple-system, BlinkMacSystemFont, sans-serif',\n size: 12,\n color: '#e0e0e0'\n }\n },\n // 3D scene defaults\n scene: {\n xaxis: {\n gridcolor: '#333333',\n linecolor: '#444444',\n backgroundcolor: 'rgba(0,0,0,0)'\n },\n yaxis: {\n gridcolor: '#333333',\n linecolor: '#444444',\n backgroundcolor: 'rgba(0,0,0,0)'\n },\n zaxis: {\n gridcolor: '#333333',\n linecolor: '#444444',\n backgroundcolor: 'rgba(0,0,0,0)'\n },\n bgcolor: 'rgba(0,0,0,0)'\n }\n};\n\n/** The PNG export's file name (without extension) when the embedder names none. */\nexport const DEFAULT_CHART_EXPORT_FILENAME = 'chart';\n\n/**\n * Default Plotly config options\n */\nexport const DEFAULT_CONFIG = {\n responsive: true,\n displaylogo: false,\n displayModeBar: false, // Hide modebar completely\n scrollZoom: true, // Allow zoom with scroll wheel instead\n toImageButtonOptions: {\n format: 'png',\n filename: DEFAULT_CHART_EXPORT_FILENAME,\n scale: 2\n }\n};\n\n/**\n * Name the file a chart's PNG export saves as (Plotly adds `.png`). Applies to\n * every chart created afterwards through DEFAULT_CONFIG; a chart's own\n * `config.toImageButtonOptions` still wins.\n *\n * @param {string} [filename=DEFAULT_CHART_EXPORT_FILENAME]\n */\nexport function setChartExportFilename(filename = DEFAULT_CHART_EXPORT_FILENAME) {\n DEFAULT_CONFIG.toImageButtonOptions.filename =\n (typeof filename === 'string' && filename) ? filename : DEFAULT_CHART_EXPORT_FILENAME;\n}\n\n/** @returns {string} The PNG export's file name (without extension). */\nexport function getChartExportFilename() {\n return DEFAULT_CONFIG.toImageButtonOptions.filename;\n}\n\n/**\n * Load Plotly.js from CDN.\n * Uses singleton pattern to avoid multiple loads.\n * @returns {Promise<Plotly>} The Plotly library object\n */\nexport async function ensurePlotly() {\n // Already loaded\n if (typeof Plotly !== 'undefined') {\n return Plotly;\n }\n\n // Loading in progress\n if (_plotlyLoadPromise) {\n return _plotlyLoadPromise;\n }\n\n if (!_plotlySrc) {\n throw new Error(\n '[twm/charts] Plotly is not loaded and no source is configured. '\n + 'Either load Plotly yourself (a <script> tag that sets window.Plotly), '\n + 'or call setPlotlySource(\"/path/to/plotly.min.js\") before rendering a chart.');\n }\n\n // Start loading \u2014 make Plotly's UMD header take its browser-global branch\n // WITHOUT asking any other script on the page to give up AMD, even for a\n // moment.\n //\n // \u2550\u2550 WHY THE SCRIPT TAG IS NOT USED FIRST \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n //\n // Plotly's header asks one question \u2014 `typeof define === 'function' &&\n // define.amd` \u2014 and takes the AMD branch if the answer is yes, leaving\n // `window.Plotly` unset because nothing calls the anonymous module back. A\n // `<script>` tag therefore has to change what that question answers, and a\n // global is the only place to change it. That is what this function used to\n // do: it hid `define.amd` for the length of the fetch (see\n // `loadThroughMaskedDefine` below for the two ways a cruder version of that\n // breaks).\n //\n // MASKING IS STILL WRONG, AND MONACO IS THE PROOF. The window lasts as long\n // as a 4.4 MB download, and any OTHER script that executes inside it asks\n // the same question and gets the answer meant for Plotly. Monaco's\n // `editor.main.js` \u2014 3.7 MB, fetched on demand, so it lands wherever it\n // lands \u2014 asks it twice:\n //\n // typeof define==\"function\"&&define.amd ? define(ne[447], \u2026) // marked\n // \u2026 || typeof define==\"function\"&&define.amd) && (globalThis.monaco = m)\n //\n // The first is the copy of `marked` bundled INSIDE `editor.main.js`. Told\n // there is no AMD, it registers itself as `globalThis.marked` instead of as\n // the module `vs/base/common/marked/marked` \u2014 so Monaco's loader goes\n // looking for that module as a FILE, which the `min` distribution does not\n // ship (it is bundled, precisely here). The 404 fails the whole\n // `vs/editor/editor.main` require:\n //\n // Loading \"vs/base/common/marked/marked\" failed\n // Here are the modules that depend on it: vs/base/browser/markdownRenderer\n //\n // The second means `window.monaco` is never set even if the first is\n // survived. Monaco's `monacoReady` has no reject path, so neither shows up\n // as a failure: the editor simply never arrives, for the life of the page,\n // and every consumer sits in its textarea fallback. Measured on the running\n // deployment on 2026-09-04: 5 boots in 8 lost Monaco this way, 0 in 8 with\n // the Plotly warm-up removed.\n //\n // \u2550\u2550 SO THE GLOBALS ARE NOT TOUCHED AT ALL \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n //\n // Fetch the source, then evaluate it in a function whose PARAMETERS are\n // named `define`, `module` and `exports`. Inside that scope `typeof define`\n // is \"undefined\" \u2014 the answer Plotly needs \u2014 while `window.define` is never\n // read, written or deleted, so no other script can observe anything. The\n // window is not a window at all: it is one synchronous evaluation, and\n // nothing else can run inside it by construction.\n //\n // The masked-tag path stays as the FALLBACK for a source this page cannot\n // fetch \u2014 a CDN without CORS is the case that matters, and it is exactly the\n // case where a `<script>` tag still works.\n _plotlyLoadPromise = (async () => {\n let code;\n try {\n const response = await fetch(_plotlySrc, { credentials: 'same-origin' });\n if (!response.ok) throw new Error(`HTTP ${response.status}`);\n code = await response.text();\n } catch (err) {\n // The FETCH failed, which a tag may still survive. An evaluation\n // failure is not caught here: it would fail identically through a\n // tag, and swallowing it would replace a real message with a\n // misleading one.\n return loadThroughMaskedDefine();\n }\n return evaluateWithoutAmd(code, _plotlySrc);\n })();\n\n return _plotlyLoadPromise;\n}\n\n/**\n * Run Plotly's bundle with the three UMD globals shadowed as local names.\n *\n * `new Function` is not strict, so `this` is the global object inside the body \u2014\n * which is what Plotly's header is invoked with (`}(self, \u2026)` in 2.x, `this` in\n * older builds), and is why the browser-global branch still lands `Plotly` on\n * the window rather than on a scope that disappears.\n *\n * @param {string} code the bundle's source\n * @param {string} src where it came from, for the debugger's file list\n * @returns {object} the `Plotly` global\n */\nfunction evaluateWithoutAmd(code, src) {\n // eslint-disable-next-line no-new-func\n const run = new Function('define', 'module', 'exports',\n `${code}\\n//# sourceURL=${src}`);\n run(undefined, undefined, undefined);\n if (typeof Plotly === 'undefined') {\n throw new Error(`Plotly.js was evaluated from ${src} but did not define a `\n + 'Plotly global \u2014 the file may not be a Plotly UMD bundle.');\n }\n return Plotly;\n}\n\n/**\n * The `<script>` tag path, for a source this page cannot fetch.\n *\n * \u2550\u2550 WHY `define` IS MASKED AND NOT REMOVED \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n *\n * Hiding `window.define` outright breaks the page two ways, both observed on a\n * running deployment on 2026-08-31:\n *\n * 1. `window.define = undefined`, restored on load. Monaco's `loader.js`\n * installs an AMD loader DURING the window, Plotly's header then sees\n * `typeof define === 'function' && define.amd`, registers as an anonymous\n * module nothing calls back, and the load \"succeeds\" with `window.Plotly`\n * still undefined:\n * This chart could not be drawn: Plotly.js loaded but Plotly global\n * not found\n * \u2014 true, unhelpful, and it sends the reader hunting for a missing file\n * that is being served correctly.\n *\n * 2. The mirror. Monaco loads in TWO stages: `loader.js` sets `define`, and\n * `editor.main.js` arrives later and calls it. If stage two lands while\n * `define` is hidden:\n * editor.main.js:5 Uncaught TypeError: globalDefine is not a function\n * One race costs the chart; the other costs the editor.\n *\n * Masking the PROPERTY rather than the function fixes both \u2014 `define` stays\n * callable, `amd` is withheld \u2014 and it is still not safe for anybody else who\n * asks the `define.amd` question inside the window. `ensurePlotly` says what\n * that costs; this path is taken only when there is no alternative.\n *\n * @returns {Promise<object>} the `Plotly` global\n */\nfunction loadThroughMaskedDefine() {\n return new Promise((resolve, reject) => {\n const hadDefine = 'define' in window;\n const savedDefine = window.define;\n let arrivedDefine; // what somebody installed mid-window\n let arrived = false;\n let guarded = false;\n\n /** The same function with `amd` withheld. Plotly reads `define.amd` and\n * stops; everyone else calls it and it behaves. */\n const maskAmd = (value) => {\n if (typeof value !== 'function') return undefined;\n const masked = function define(...args) { return value.apply(this, args); };\n for (const key of Object.getOwnPropertyNames(value)) {\n if (key === 'amd' || key === 'length' || key === 'name') continue;\n try { masked[key] = value[key]; } catch { /* getters that throw */ }\n }\n masked.amd = undefined;\n return masked;\n };\n\n try {\n Object.defineProperty(window, 'define', {\n configurable: true,\n enumerable: true,\n get: () => maskAmd(arrived ? arrivedDefine : savedDefine),\n set: (value) => { arrivedDefine = value; arrived = true; },\n });\n guarded = true;\n } catch {\n // A host that refuses the redefinition still gets the old\n // behaviour, which is right far more often than it is wrong.\n window.define = undefined;\n }\n\n /** Put the REAL `define` back, exactly once, preferring what arrived. */\n const release = () => {\n const value = arrived ? arrivedDefine : savedDefine;\n if (guarded) {\n delete window.define;\n guarded = false;\n }\n // `hadDefine` matters: assigning `undefined` leaves an own property\n // whose value is undefined, and `'define' in window` then answers\n // true for a global that was never there. Some loaders test that.\n if (arrived || hadDefine) window.define = value;\n };\n\n const script = document.createElement('script');\n script.src = _plotlySrc;\n script.async = true;\n\n script.onload = () => {\n release();\n if (typeof Plotly !== 'undefined') {\n resolve(Plotly);\n } else {\n reject(new Error('Plotly.js loaded but Plotly global not found. '\n + 'Something defined an AMD loader while it was loading, so '\n + 'Plotly registered as a module instead of a global.'));\n }\n };\n\n script.onerror = () => {\n release();\n reject(new Error(`Failed to load Plotly.js from ${_plotlySrc} \u2014 `\n + 'call setPlotlySource() with the path to your copy.'));\n };\n\n document.head.appendChild(script);\n });\n}\n\n/**\n * Create a new Plotly chart.\n * @param {HTMLElement} container - Container element for the chart\n * @param {Array} data - Array of trace objects\n * @param {Object} layout - Layout configuration\n * @param {Object} config - Plotly config options\n * @returns {Promise<HTMLElement>} The chart element\n */\nexport async function createChart(container, data, layout = {}, config = {}) {\n const Plotly = await ensurePlotly();\n\n const mergedLayout = {\n ...DARK_THEME_LAYOUT,\n ...layout\n };\n\n const mergedConfig = {\n ...DEFAULT_CONFIG,\n ...config\n };\n\n return Plotly.newPlot(container, data, mergedLayout, mergedConfig);\n}\n\n/**\n * Update chart data and layout efficiently.\n * Uses Plotly.react() which is optimized for updates.\n * @param {HTMLElement} container - Chart container\n * @param {Array} data - New trace data\n * @param {Object} layout - Layout updates\n */\nexport async function updateChart(container, data, layout = {}) {\n const Plotly = await ensurePlotly();\n\n const mergedLayout = {\n ...DARK_THEME_LAYOUT,\n ...layout\n };\n\n return Plotly.react(container, data, mergedLayout);\n}\n\n/**\n * Extend traces with new data points (for streaming).\n * More efficient than full update for appending data.\n * @param {HTMLElement} container - Chart container\n * @param {Object} update - Data to extend: { x: [[...]], y: [[...]] }\n * @param {Array<number>} traceIndices - Which traces to extend\n * @param {number} maxPoints - Maximum points to keep (optional)\n */\nexport async function extendTraces(container, update, traceIndices, maxPoints = null) {\n const Plotly = await ensurePlotly();\n\n if (maxPoints) {\n return Plotly.extendTraces(container, update, traceIndices, maxPoints);\n }\n return Plotly.extendTraces(container, update, traceIndices);\n}\n\n/**\n * Relayout chart (update layout only, no data change).\n * @param {HTMLElement} container - Chart container\n * @param {Object} layoutUpdate - Layout properties to update\n */\nexport async function relayout(container, layoutUpdate) {\n const Plotly = await ensurePlotly();\n return Plotly.relayout(container, layoutUpdate);\n}\n\n/**\n * Restyle traces (update trace properties without full redraw).\n * @param {HTMLElement} container - Chart container\n * @param {Object} styleUpdate - Style properties to update\n * @param {Array<number>} traceIndices - Which traces to update\n */\nexport async function restyle(container, styleUpdate, traceIndices) {\n const Plotly = await ensurePlotly();\n return Plotly.restyle(container, styleUpdate, traceIndices);\n}\n\n/**\n * Delete all traces and release resources.\n * @param {HTMLElement} container - Chart container\n */\nexport async function purge(container) {\n const Plotly = await ensurePlotly();\n return Plotly.purge(container);\n}\n\n/**\n * Check if container has a Plotly chart.\n * @param {HTMLElement} container - Container element\n * @returns {boolean}\n */\nexport function hasPlot(container) {\n return container && container._fullLayout !== undefined;\n}\n\n/**\n * Resize chart to fit container.\n * Call this when container size changes.\n * @param {HTMLElement} container - Chart container\n */\nexport async function resize(container) {\n const Plotly = await ensurePlotly();\n return Plotly.Plots.resize(container);\n}\n\n/**\n * Convert hex color to rgba.\n * @param {string} hex - Hex color code\n * @param {number} alpha - Alpha value (0-1)\n * @returns {string} rgba color string\n */\nexport function hexToRgba(hex, alpha = 1) {\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\n if (!result) return hex;\n const r = parseInt(result[1], 16);\n const g = parseInt(result[2], 16);\n const b = parseInt(result[3], 16);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n\n// Solarized theme colors matching legacy plot_node.js\nexport const COLOR_PALETTE = [\n '#268bd2', // Solarized Blue\n '#d33682', // Solarized Magenta\n '#cb4b16', // Solarized Orange\n '#2aa198', // Solarized Cyan\n '#6a5acd', // SlateBlue/Purple\n '#7a7d80', // Gray\n '#9fb6cf', // Gray-Blue\n];\n\n/**\n * Get color from palette by index.\n * @param {number} index - Series index\n * @returns {string} Color hex code\n */\nexport function getSeriesColor(index) {\n return COLOR_PALETTE[index % COLOR_PALETTE.length];\n}\n\n/**\n * Create a Plotly chart with deferred rendering support.\n * Handles zero-dimension containers by waiting for valid dimensions via ResizeObserver.\n * @param {HTMLElement} container - Container element for the chart\n * @param {Array} traces - Array of trace objects\n * @param {Object} layout - Layout configuration\n * @param {Object} config - Plotly config options\n * @returns {Promise<{element: HTMLElement, cleanup: Function}>} Chart element and cleanup function\n */\nexport async function createChartDeferred(container, traces, layout = {}, config = {}) {\n const Plotly = await ensurePlotly();\n\n const mergedLayout = {\n ...DARK_THEME_LAYOUT,\n ...layout\n };\n\n const mergedConfig = {\n ...DEFAULT_CONFIG,\n ...config\n };\n\n const w = container.offsetWidth;\n const h = container.offsetHeight;\n\n // Cleanup function to return\n let resizeObserver = null;\n const cleanup = () => {\n if (resizeObserver) {\n resizeObserver.disconnect();\n resizeObserver = null;\n }\n };\n\n // If dimensions are valid, render immediately\n if (w > 0 && h > 0) {\n await Plotly.newPlot(container, traces, mergedLayout, mergedConfig);\n // Still set up resize observer for ongoing resizes\n resizeObserver = createRafResizeObserver(() => {\n if (hasPlot(container)) {\n Plotly.Plots.resize(container).catch(() => {});\n }\n });\n resizeObserver.observe(container);\n return { element: container, cleanup };\n }\n\n // Dimensions are zero - wait for valid dimensions via ResizeObserver\n return new Promise((resolve) => {\n let rendered = false;\n resizeObserver = createRafResizeObserver((entries) => {\n for (const entry of entries) {\n const { width, height } = entry.contentRect;\n if (width > 0 && height > 0) {\n if (!rendered) {\n rendered = true;\n Plotly.newPlot(container, traces, mergedLayout, mergedConfig).then(() => {\n resolve({ element: container, cleanup });\n }).catch(() => {\n resolve({ element: container, cleanup });\n });\n } else if (hasPlot(container)) {\n // Handle subsequent resizes\n Plotly.Plots.resize(container).catch(() => {});\n }\n }\n }\n });\n resizeObserver.observe(container);\n });\n}\n", "/**\n * Chart Types and Trace Configurations\n *\n * Defines trace configurations for Plotly.js and provides mapping\n * from Chart.js options to Plotly equivalents.\n */\n\nimport { getSeriesColor, hexToRgba } from './plotly_wrapper.js';\n\n/**\n * Available 2D chart types\n */\nexport const CHART_TYPES_2D = Object.freeze([\n { value: 'line', label: 'Line' },\n { value: 'bar', label: 'Bar' },\n { value: 'scatter', label: 'Scatter' },\n { value: 'area', label: 'Area' },\n { value: 'area-stacked', label: 'Area (Stacked %)' },\n { value: 'phase', label: 'Phase' },\n // Categorical part-of-whole. They belong in this list because the list is\n // what a consumer renders as its chart-type dropdown \u2014 but they are NOT\n // (x[], y[]) charts, and `buildTrace` leaves for them before the switch:\n // read the early return there before adding a fourth. `indicator` is\n // deliberately NOT here, because it takes a SCALAR \u2014 a dropdown offering it\n // beside these would offer a rendering of data the chart is not bound to.\n { value: 'pie', label: 'Pie' },\n { value: 'donut', label: 'Donut' },\n { value: 'funnel', label: 'Funnel' },\n]);\n\n/**\n * Available 3D chart types\n */\nexport const CHART_TYPES_3D = Object.freeze([\n { value: 'scatter3d', label: '3D Scatter' },\n { value: 'line3d', label: '3D Line' },\n { value: 'surface', label: '3D Surface' },\n]);\n\n/**\n * All chart types combined\n */\nexport const ALL_CHART_TYPES = Object.freeze([...CHART_TYPES_2D, ...CHART_TYPES_3D]);\n\n/**\n * Check if chart type is 3D\n * @param {string} chartType\n * @returns {boolean}\n */\nexport function is3DChart(chartType) {\n return ['scatter3d', 'line3d', 'surface'].includes(chartType);\n}\n\n/**\n * Line style mapping (Chart.js borderDash to Plotly dash)\n */\nconst LINE_DASH_MAP = {\n solid: 'solid',\n dashed: 'dash',\n dotted: 'dot',\n};\n\n/**\n * Interpolation mapping (Chart.js to Plotly line shape). 'auto' draws straight\n * segments between the points, as 'linear' does.\n */\nconst INTERPOLATION_MAP = {\n linear: 'linear',\n step: 'hv', // horizontal-vertical step\n cubic: 'spline', // smooth spline\n auto: 'linear',\n};\n\n/**\n * Build a Plotly trace from series configuration.\n * @param {Object} options\n * @param {string} options.chartType - Chart type (line, bar, scatter, area, scatter3d, etc.)\n * @param {Array} options.x - X-axis data\n * @param {Array} options.y - Y-axis data\n * @param {Array} [options.z] - Z-axis data (for 3D charts)\n * @param {string} options.name - Series name/label\n * @param {string} [options.color] - Series color (hex)\n * @param {number} [options.lineWidth] - Line width in pixels\n * @param {string} [options.lineStyle] - Line style: solid, dashed, dotted\n * @param {string} [options.interpolation] - Interpolation: linear, step, cubic, or auto (drawn as linear)\n * @param {string} [options.yAxisId] - Y-axis identifier (y, y2, y3, etc.)\n * @param {boolean} [options.showMarkers] - Show data point markers\n * @param {number} [options.seriesIndex] - Index for default color selection\n * @param {Array<string>} [options.colors] - Per-CATEGORY colors, pie/donut/funnel only\n * @returns {Object} Plotly trace object\n */\nexport function buildTrace(options) {\n const {\n chartType = 'line',\n x = [],\n y = [],\n z = null,\n name = 'Series',\n color = null,\n lineWidth = 2,\n lineStyle = 'solid',\n interpolation = 'linear',\n yAxisId = 'y',\n showMarkers = false,\n seriesIndex = 0,\n stackGroup = null,\n colors = null,\n } = options;\n\n const seriesColor = color || getSeriesColor(seriesIndex);\n\n // \u2500\u2500 categorical part-of-whole: pie, donut, funnel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n // These leave here, ABOVE the switch, and that placement is the whole\n // point rather than a tidiness. Everything below is written against the\n // base trace built at the end of the switch \u2014 `{type, name, x, y}` \u2014 and a\n // pie has neither an x nor a y: Plotly reads `labels` and `values`, and a\n // stray `x` rides along ignored right up until someone puts the trace on a\n // shared axis and it is not ignored any more.\n //\n // The marker block further down is the sharper edge. It fires on\n // `showMarkers` for ANY chart type and assigns `marker = {color, size}` \u2014\n // which would overwrite `marker.colors`, the per-slice palette, with one\n // scalar colour and turn a seven-slice pie into a single blue disc. A\n // `case` in the switch cannot avoid either hazard; leaving before both can.\n if (chartType === 'pie' || chartType === 'donut' || chartType === 'funnel') {\n // `seriesIndex` is not consulted: a pie IS the chart, so its slices\n // start at the top of the palette rather than continuing someone\n // else's series numbering.\n const sliceColors = Array.isArray(colors) && colors.length\n ? colors\n : y.map((_, i) => getSeriesColor(i));\n\n if (chartType === 'funnel') {\n // A funnel is bar-shaped, so it is `marker.color` (singular, and\n // an array is legal) \u2014 NOT the `marker.colors` a pie wants. The\n // two spellings are not interchangeable and neither errors.\n return {\n type: 'funnel',\n name,\n y: x, // stages read down the categorical axis\n x: y, // ...and the measure runs across\n marker: { color: sliceColors },\n textinfo: 'value+percent initial',\n };\n }\n\n return {\n type: 'pie',\n name,\n labels: x,\n values: y,\n marker: { colors: sliceColors },\n // Plotly sorts slices descending by default. The caller has\n // already ordered its rows \u2014 a dashboard binding carries its own\n // `sort` \u2014 and a second, invisible reordering here makes the chart\n // disagree with the table beside it and with the config that\n // produced both.\n sort: false,\n ...(chartType === 'donut' ? { hole: 0.55 } : {}),\n };\n }\n\n // Determine Plotly trace type and mode\n let plotlyType, mode;\n switch (chartType) {\n case 'line':\n plotlyType = 'scatter';\n mode = showMarkers ? 'lines+markers' : 'lines';\n break;\n case 'scatter':\n plotlyType = 'scatter';\n mode = 'markers';\n break;\n case 'area':\n case 'area-stacked':\n plotlyType = 'scatter';\n mode = showMarkers ? 'lines+markers' : 'lines';\n break;\n case 'phase':\n plotlyType = 'scatter';\n mode = 'lines+markers';\n break;\n case 'bar':\n plotlyType = 'bar';\n mode = undefined;\n break;\n case 'scatter3d':\n plotlyType = 'scatter3d';\n mode = 'markers';\n break;\n case 'line3d':\n plotlyType = 'scatter3d';\n mode = showMarkers ? 'lines+markers' : 'lines';\n break;\n case 'surface':\n plotlyType = 'surface';\n mode = undefined;\n break;\n default:\n plotlyType = 'scatter';\n mode = showMarkers ? 'lines+markers' : 'lines';\n }\n\n // Build base trace\n const trace = {\n type: plotlyType,\n name,\n x,\n y,\n };\n\n // Add mode if applicable\n if (mode) {\n trace.mode = mode;\n }\n\n // Add z-axis data for 3D charts\n if (z && is3DChart(chartType)) {\n // Surface charts require z to be a 2D array\n // If z is 1D (time series data), use mesh3d with Delaunay triangulation\n if (chartType === 'surface') {\n const zIs2D = Array.isArray(z) && z.length > 0 && Array.isArray(z[0]);\n if (zIs2D) {\n trace.z = z;\n } else {\n // Use mesh3d with Delaunay triangulation for 1D scattered points\n console.info('[chart_types] Surface chart with 1D z data - using mesh3d with Delaunay triangulation');\n trace.type = 'mesh3d';\n trace.x = x;\n trace.y = y;\n trace.z = z;\n trace.alphahull = 0; // Delaunay triangulation (convex hull = -1, 0 = Delaunay)\n trace.opacity = 0.8;\n trace.color = seriesColor;\n trace.flatshading = true;\n trace.lighting = {\n ambient: 0.6,\n diffuse: 0.5,\n specular: 0.2,\n };\n // Skip surface-specific config below\n return trace;\n }\n } else {\n trace.z = z;\n }\n }\n\n // Phase chart: line with small markers\n if (chartType === 'phase') {\n trace.line = {\n color: seriesColor,\n width: lineWidth,\n dash: LINE_DASH_MAP[lineStyle] || 'solid',\n };\n trace.marker = {\n color: seriesColor,\n size: 3,\n };\n return trace;\n }\n\n // Line configuration (for line/area charts)\n if (['line', 'area', 'area-stacked', 'line3d'].includes(chartType)) {\n trace.line = {\n color: seriesColor,\n width: lineWidth,\n dash: LINE_DASH_MAP[lineStyle] || 'solid',\n shape: INTERPOLATION_MAP[interpolation] || 'linear',\n };\n }\n\n // Marker configuration\n if (['scatter', 'scatter3d'].includes(chartType) || showMarkers) {\n trace.marker = {\n color: seriesColor,\n size: chartType === 'scatter3d' ? 4 : 6,\n };\n }\n\n // Normalized stacked area: each Y-axis is its own stack group, each summing to 1.\n if (chartType === 'area-stacked') {\n trace.stackgroup = yAxisId;\n trace.groupnorm = 'fraction';\n trace.fillcolor = hexToRgba(seriesColor, 0.5);\n trace.line = { ...(trace.line || {}), width: 0.5, color: seriesColor };\n trace.mode = 'lines';\n }\n // Fill for area charts (non-stacked)\n else if (chartType === 'area' && !stackGroup) {\n trace.fill = 'tozeroy';\n trace.fillcolor = hexToRgba(seriesColor, 0.3);\n }\n // Stacked area via explicit stackGroup on any chart type\n else if (stackGroup) {\n trace.stackgroup = stackGroup;\n trace.fillcolor = hexToRgba(seriesColor, 0.5);\n trace.line = { ...(trace.line || {}), width: 0.5, color: seriesColor };\n trace.mode = 'lines';\n }\n\n // Bar color\n if (chartType === 'bar') {\n trace.marker = {\n color: seriesColor,\n };\n }\n\n // Surface colorscale\n if (chartType === 'surface') {\n trace.colorscale = 'Viridis';\n trace.showscale = true;\n }\n\n // Y-axis assignment (for multi-axis support)\n if (!is3DChart(chartType) && yAxisId && yAxisId !== 'y') {\n trace.yaxis = yAxisId;\n }\n\n return trace;\n}\n\n/**\n * Build layout for Y-axis based on configuration.\n * @param {Object} options\n * @param {string} options.axisId - Axis identifier (y, y2, y3, etc.)\n * @param {string} [options.title] - Axis title\n * @param {string} [options.position] - Axis position: left or right\n * @param {string} [options.scaleType] - Scale type: linear or log\n * @param {number} [options.min] - Minimum value\n * @param {number} [options.max] - Maximum value\n * @param {number} [options.step] - Tick step size\n * @param {boolean} [options.showGrid] - Show grid lines\n * @param {number|null} [options.axisPosition] - Explicit position in normalized coords (0-1), null for default\n * @returns {Object} Plotly axis layout object\n */\nexport function buildYAxisLayout(options) {\n const {\n axisId = 'yaxis',\n title = '',\n position = 'left',\n scaleType = 'linear',\n min = null,\n max = null,\n step = null,\n showGrid = true,\n axisPosition = null,\n } = options;\n\n const layout = {\n title: { text: title },\n type: scaleType === 'log' ? 'log' : 'linear',\n side: position,\n gridcolor: 'rgba(255,255,255,0.05)',\n linecolor: 'rgba(255,255,255,0.08)',\n tickcolor: 'rgba(255,255,255,0.3)',\n zerolinecolor: 'rgba(255,255,255,0.06)',\n showgrid: showGrid,\n automargin: true, // Auto-expand margin for tick labels\n };\n\n // Set range if min/max provided.\n // Both bounds: fixed range (autorange off).\n // One-sided: use autorangeoptions so Plotly auto-ranges within data but respects the cap/floor.\n // Plotly does not accept null in a range array \u2014 [null, max] silently sets the lower bound to 0.\n if (min !== null && max !== null) {\n layout.autorange = false;\n layout.range = [min, max];\n } else if (min !== null || max !== null) {\n layout.autorange = true;\n layout.autorangeoptions = {};\n if (min !== null) layout.autorangeoptions.minallowed = min;\n if (max !== null) layout.autorangeoptions.maxallowed = max;\n }\n\n // Set tick step if provided\n if (step !== null && step > 0) {\n layout.dtick = step;\n }\n\n // For secondary axes, overlay on the first y-axis\n if (axisId !== 'yaxis') {\n layout.overlaying = 'y';\n layout.anchor = 'free';\n\n // Use explicit position if provided (for proper multi-axis layout)\n // axisPosition is in normalized figure coordinates (0-1)\n if (axisPosition !== null) {\n layout.position = axisPosition;\n } else {\n // Fallback: position at domain edge (0 for left, 1 for right)\n layout.position = position === 'left' ? 0 : 1;\n }\n }\n\n return layout;\n}\n\n/**\n * Build X-axis layout.\n * @param {Object} options\n * @param {string} [options.title] - Axis title\n * @param {string} [options.scaleType] - Scale type: linear or log\n * @param {number} [options.min] - Minimum value\n * @param {number} [options.max] - Maximum value\n * @returns {Object} Plotly xaxis layout object\n */\nexport function buildXAxisLayout(options) {\n const {\n title = 'Time',\n scaleType = 'linear',\n min = null,\n max = null,\n } = options;\n\n const layout = {\n title: { text: title },\n type: scaleType === 'log' ? 'log' : 'linear',\n gridcolor: 'rgba(255,255,255,0.05)',\n linecolor: 'rgba(255,255,255,0.08)',\n tickcolor: 'rgba(255,255,255,0.3)',\n zerolinecolor: 'rgba(255,255,255,0.06)',\n automargin: true,\n };\n\n if (min !== null || max !== null) {\n layout.range = [min, max];\n }\n\n return layout;\n}\n\n/**\n * Build 3D scene layout.\n * @param {Object} options\n * @param {string} [options.xTitle] - X-axis title\n * @param {string} [options.yTitle] - Y-axis title\n * @param {string} [options.zTitle] - Z-axis title\n * @param {string} [options.zScale] - Z-axis scale type: 'linear' or 'log'\n * @param {number} [options.zMin] - Z-axis minimum value\n * @param {number} [options.zMax] - Z-axis maximum value\n * @param {number} [options.zStep] - Z-axis tick step size\n * @returns {Object} Plotly scene layout object\n */\nexport function build3DSceneLayout(options) {\n const {\n xTitle = 'X',\n yTitle = 'Y',\n zTitle = 'Z',\n zScale = 'linear',\n zMin = null,\n zMax = null,\n zStep = null,\n } = options;\n\n const zaxis = {\n title: { text: zTitle },\n type: zScale === 'log' ? 'log' : 'linear',\n gridcolor: 'rgba(255,255,255,0.05)',\n linecolor: 'rgba(255,255,255,0.08)',\n backgroundcolor: 'rgba(0,0,0,0)',\n };\n\n // Set range if min/max provided\n if (zMin !== null || zMax !== null) {\n zaxis.range = [zMin, zMax];\n }\n\n // Set tick step if provided\n if (zStep !== null && zStep > 0) {\n zaxis.dtick = zStep;\n }\n\n return {\n xaxis: {\n title: { text: xTitle },\n gridcolor: 'rgba(255,255,255,0.05)',\n linecolor: 'rgba(255,255,255,0.08)',\n backgroundcolor: 'rgba(0,0,0,0)',\n },\n yaxis: {\n title: { text: yTitle },\n gridcolor: 'rgba(255,255,255,0.05)',\n linecolor: 'rgba(255,255,255,0.08)',\n backgroundcolor: 'rgba(0,0,0,0)',\n },\n zaxis,\n bgcolor: 'rgba(0,0,0,0)',\n };\n}\n\n/**\n * Build legend layout.\n * @param {string} position - Legend position: top, bottom, left, right, hidden\n * @returns {Object} Plotly legend layout\n */\nexport function buildLegendLayout(position) {\n if (position === 'hidden') {\n return { showlegend: false };\n }\n\n const baseLayout = {\n showlegend: true,\n bgcolor: 'rgba(0,0,0,0)',\n font: { color: '#cccccc' },\n };\n\n switch (position) {\n case 'top':\n return {\n ...baseLayout,\n legend: {\n ...baseLayout,\n orientation: 'h',\n y: 1.1,\n yanchor: 'bottom',\n x: 0.5,\n xanchor: 'center',\n },\n };\n case 'bottom':\n return {\n ...baseLayout,\n legend: {\n ...baseLayout,\n orientation: 'h',\n y: -0.15,\n yanchor: 'top',\n x: 0.5,\n xanchor: 'center',\n },\n };\n case 'left':\n return {\n ...baseLayout,\n legend: {\n ...baseLayout,\n orientation: 'v',\n x: -0.15,\n xanchor: 'right',\n y: 0.5,\n yanchor: 'middle',\n },\n };\n case 'right':\n default:\n return {\n ...baseLayout,\n legend: {\n ...baseLayout,\n orientation: 'v',\n x: 1.02,\n xanchor: 'left',\n y: 0.5,\n yanchor: 'middle',\n },\n };\n }\n}\n\n/**\n * Build Plotly layout shapes + annotations for reference lines and shaded x-bands.\n *\n * @param {Object} opts\n * @param {Array<{yAxisId?:string, value:number, label?:string, color?:string, lineStyle?:string, lineWidth?:number, labelX?:number}>} [opts.referenceLines]\n * Horizontal threshold lines drawn across the plot, anchored to a specific Y axis.\n * `yAxisId` matches an axis id in sp.yAxes[].id; omitted \u2192 first axis.\n * @param {Array<{x0:number, x1:number, label?:string, color?:string, opacity?:number, labelY?:number, labelColor?:string}>} [opts.shadedBands]\n * Vertical stripes (rectangles spanning full y range) to mark policy/recession periods.\n * @param {Array<{x:(number|string|Date), label?:string, color?:string, lineStyle?:string, lineWidth?:number, labelY?:number}>} [opts.verticalLines]\n * Vertical markers at one x \u2014 a \"today\" line on a burndown. Drawn full height\n * (`yref: 'paper'`), after the reference lines, so a call without them builds\n * exactly what it built before they existed. `x` is in the x axis's own units:\n * a number, a category, or a date string/Date on a date axis.\n * @param {Object<string,string>} [opts.yRefByAxisId]\n * Mapping from subplot yAxes[i].id \u2192 Plotly yref ('y', 'y2', ...).\n * @returns {{shapes: Array, annotations: Array}}\n */\nexport function buildOverlayShapes(opts = {}) {\n const { referenceLines = [], shadedBands = [], verticalLines = [], yRefByAxisId = {} } = opts;\n const shapes = [];\n const annotations = [];\n const dashMap = { solid: 'solid', dashed: 'dash', dotted: 'dot', dashdot: 'dashdot' };\n\n for (const band of shadedBands) {\n if (band.x0 == null || band.x1 == null) continue;\n shapes.push({\n type: 'rect',\n xref: 'x',\n yref: 'paper',\n x0: band.x0,\n x1: band.x1,\n y0: 0,\n y1: 1,\n fillcolor: band.color || 'rgba(255, 200, 0, 0.08)',\n line: { width: 0 },\n opacity: band.opacity ?? 1,\n layer: 'below',\n });\n if (band.label) {\n annotations.push({\n x: (band.x0 + band.x1) / 2,\n y: band.labelY ?? 1.0,\n xref: 'x',\n yref: 'paper',\n text: band.label,\n showarrow: false,\n font: { size: 9, color: band.labelColor || 'rgba(255,255,255,0.55)' },\n xanchor: 'center',\n yanchor: 'bottom',\n });\n }\n }\n\n const firstYRef = Object.values(yRefByAxisId)[0] || 'y';\n for (const ref of referenceLines) {\n if (ref.value == null || !Number.isFinite(ref.value)) continue;\n const yRef = (ref.yAxisId && yRefByAxisId[ref.yAxisId]) || firstYRef;\n const color = ref.color || 'rgba(255, 120, 120, 0.75)';\n shapes.push({\n type: 'line',\n xref: 'paper',\n yref: yRef,\n x0: 0,\n x1: 1,\n y0: ref.value,\n y1: ref.value,\n line: {\n color,\n width: ref.lineWidth ?? 1.5,\n dash: dashMap[ref.lineStyle || 'dashed'] || 'dash',\n },\n layer: 'above',\n });\n if (ref.label) {\n annotations.push({\n x: ref.labelX ?? 0.015,\n y: ref.value,\n xref: 'paper',\n yref: yRef,\n text: ref.label,\n showarrow: false,\n font: { size: 10, color },\n xanchor: 'left',\n yanchor: 'bottom',\n bgcolor: 'rgba(20,22,26,0.6)',\n borderpad: 2,\n });\n }\n }\n\n for (const mark of verticalLines) {\n // `0` is a real x, so the test is null/undefined/NaN \u2014 never truthiness.\n if (mark == null || mark.x == null || (typeof mark.x === 'number' && !Number.isFinite(mark.x))) continue;\n const color = mark.color || 'rgba(255, 200, 0, 0.75)';\n shapes.push({\n type: 'line',\n xref: 'x',\n yref: 'paper',\n x0: mark.x,\n x1: mark.x,\n y0: 0,\n y1: 1,\n line: {\n color,\n width: mark.lineWidth ?? 1.5,\n dash: dashMap[mark.lineStyle || 'dashed'] || 'dash',\n },\n layer: 'above',\n });\n if (mark.label) {\n annotations.push({\n x: mark.x,\n y: mark.labelY ?? 1.0,\n xref: 'x',\n yref: 'paper',\n text: mark.label,\n showarrow: false,\n font: { size: 10, color },\n xanchor: 'left',\n yanchor: 'bottom',\n });\n }\n }\n\n return { shapes, annotations };\n}\n\n/**\n * Create a fan chart trace with confidence bands.\n * @param {Object} options\n * @param {Array} options.x - X-axis data (time)\n * @param {Array} options.upper - Upper bound data\n * @param {Array} options.lower - Lower bound data\n * @param {string} options.color - Band color\n * @param {number} options.opacity - Fill opacity\n * @param {string} [options.name] - Band name for legend\n * @returns {Array} Array of two traces (lower bound + fill to upper)\n */\nexport function buildFanBandTraces(options) {\n const { x, upper, lower, color, opacity = 0.2, name = '' } = options;\n\n // Lower bound line (invisible, for fill reference)\n const lowerTrace = {\n type: 'scatter',\n x,\n y: lower,\n mode: 'lines',\n line: { width: 0 },\n showlegend: false,\n hoverinfo: 'skip',\n };\n\n // Upper bound with fill to lower\n const upperTrace = {\n type: 'scatter',\n x,\n y: upper,\n mode: 'lines',\n line: { width: 0 },\n fill: 'tonexty',\n fillcolor: hexToRgba(color, opacity),\n name: name || `${(opacity * 100).toFixed(0)}% Band`,\n showlegend: !!name,\n };\n\n return [lowerTrace, upperTrace];\n}\n\n/**\n * Create a histogram trace.\n * @param {Object} options\n * @param {Array} options.x - Data values\n * @param {number} options.nbins - Number of bins\n * @param {string} options.color - Bar color\n * @param {string} [options.name] - Series name\n * @returns {Object} Plotly histogram trace\n */\nexport function buildHistogramTrace(options) {\n const { x, nbins = 20, color, name = 'Distribution' } = options;\n\n return {\n type: 'histogram',\n x,\n nbinsx: nbins,\n marker: { color },\n name,\n };\n}\n\n/**\n * Create a box plot trace.\n * @param {Object} options\n * @param {Array} options.y - Data values\n * @param {string} [options.x] - Category/time label\n * @param {string} options.color - Box color\n * @param {string} [options.name] - Series name\n * @returns {Object} Plotly box trace\n */\nexport function buildBoxTrace(options) {\n const { y, x = null, color, name = '' } = options;\n\n const trace = {\n type: 'box',\n y,\n marker: { color },\n name,\n boxpoints: false, // Don't show individual points\n };\n\n if (x !== null) {\n trace.x = Array.isArray(x) ? x : [x];\n }\n\n return trace;\n}\n\n/**\n * Create a heatmap trace.\n * @param {Object} options\n * @param {Array} options.z - 2D array of values\n * @param {Array} [options.x] - X labels\n * @param {Array} [options.y] - Y labels\n * @param {string} [options.colorscale] - Plotly colorscale name\n * @returns {Object} Plotly heatmap trace\n */\nexport function buildHeatmapTrace(options) {\n const { z, x = null, y = null, colorscale = 'RdBu' } = options;\n\n const trace = {\n type: 'heatmap',\n z,\n colorscale,\n showscale: true,\n };\n\n if (x) trace.x = x;\n if (y) trace.y = y;\n\n return trace;\n}\n\n// Delta sense, in the palette's own idiom (Solarized, per COLOR_PALETTE). A\n// caller whose metric is better when it falls \u2014 cost, latency, churn \u2014 passes\n// its own two colours rather than expecting a flag here: \"up is good\" is a\n// property of the measure, and this file has never been told what the measure\n// is.\nconst DELTA_UP = '#859900'; // Solarized green\nconst DELTA_DOWN = '#dc322f'; // Solarized red\n\n/**\n * Create a Plotly `indicator` trace \u2014 a big number, optionally with a gauge\n * arc under it and a delta against a reference.\n *\n * This is NOT reachable through `buildTrace`, and `indicator` is not in\n * `CHART_TYPES_2D`: `buildTrace`'s contract is two parallel arrays and an\n * indicator takes a single scalar, so offering it in the same dropdown would\n * offer a rendering that cannot consume what the dropdown's chart is bound to.\n *\n * The returned object is a plain literal and yours to extend \u2014 `domain` for\n * two indicators in one div, `number.prefix` / `number.valueformat` for\n * currency. Number formatting is deliberately not a parameter: a consumer that\n * already owns a value formatter and hands Plotly a second one shows the\n * currency symbol twice, and neither side knows the other did it.\n *\n * @param {Object} options\n * @param {number} options.value - The number to show\n * @param {number} [options.min] - Gauge floor (default 0)\n * @param {number} [options.max] - Gauge ceiling; null draws NO gauge\n * @param {string} [options.title] - Label above the number\n * @param {Array<{range: number[], color: string}>} [options.steps] - Banded background\n * @param {number|{value: number, color: string, width: number, thickness: number}} [options.threshold]\n * @param {string} [options.color] - The gauge bar colour\n * @param {number} [options.seriesIndex] - Palette index when `color` is absent\n * @param {number|{reference: number, relative: boolean, increasing: string, decreasing: string}} [options.delta]\n * @returns {Object} Plotly indicator trace\n */\nexport function buildIndicatorTrace(options) {\n const {\n value,\n min = 0,\n max = null,\n title = '',\n steps = null,\n threshold = null,\n color = null,\n seriesIndex = 0,\n delta = null,\n } = options;\n\n // A gauge with no ceiling has no arc to draw. Inventing one \u2014 twice the\n // value, the next round number \u2014 draws a chart that is quietly wrong about\n // the only thing a gauge communicates, so an absent `max` degrades to the\n // bare number instead.\n const hasGauge = typeof max === 'number' && Number.isFinite(max);\n\n // `0` is an ordinary reference \u2014 last month's total was zero \u2014 so the test\n // is `typeof`, never truthiness. Under a truthiness test `delta: 0` drops\n // the comparison the tile exists to draw, silently and only sometimes.\n const deltaSpec = typeof delta === 'number' ? { reference: delta }\n : (delta && typeof delta === 'object') ? delta\n : null;\n\n const parts = ['number'];\n if (hasGauge) parts.unshift('gauge');\n if (deltaSpec) parts.push('delta');\n\n const trace = {\n type: 'indicator',\n mode: parts.join('+'),\n value,\n };\n\n if (title) trace.title = { text: title };\n\n if (deltaSpec) {\n trace.delta = {\n reference: deltaSpec.reference,\n relative: deltaSpec.relative === true,\n increasing: { color: deltaSpec.increasing || DELTA_UP },\n decreasing: { color: deltaSpec.decreasing || DELTA_DOWN },\n };\n }\n\n if (hasGauge) {\n trace.gauge = {\n axis: { range: [min, max] },\n bar: { color: color || getSeriesColor(seriesIndex) },\n };\n // Passed through rather than derived. A band means something to the\n // consumer \u2014 a target, an SLA, a red zone \u2014 and this file cannot guess\n // where it sits.\n if (Array.isArray(steps) && steps.length) trace.gauge.steps = steps;\n\n if (threshold !== null && threshold !== undefined) {\n const t = typeof threshold === 'number' ? { value: threshold } : threshold;\n trace.gauge.threshold = {\n line: { color: t.color || DELTA_DOWN, width: t.width ?? 3 },\n thickness: t.thickness ?? 0.9,\n value: t.value,\n };\n }\n }\n\n return trace;\n}\n", "/**\n * downsample.js\n *\n * Client-side time-series decimation for the render path. A long live run\n * accumulates thousands of points per series; feeding all of them to\n * Plotly.react() every refresh is what makes a running dashboard crawl.\n * These helpers cap the points actually drawn while preserving the visual\n * shape.\n *\n * Two strategies, the usual pair on the server side as well (LTTB for one\n * line, stride decimation for a stream):\n *\n * \u2022 strideDownsampleShared \u2014 one set of indices applied to the shared x\n * axis and EVERY series. Cheap, gap-safe (nulls keep their slot), and\n * alignment-safe (all series sample the same x), so it works for\n * stacked/area charts and multi-series subplots. This is the default\n * used by the dashboard tiles.\n *\n * \u2022 lttb \u2014 Largest-Triangle-Three-Buckets for a single (x, y) line.\n * Higher visual fidelity (keeps peaks/troughs) but each series picks\n * its own x, so it's only safe for independent line/scatter traces\n * with finite y. Offered for callers that want it.\n */\n\n/**\n * Pick ~targetPoints evenly-spaced indices out of [0, n), always including\n * the first and last. Returns an ascending Int array; returns null when no\n * decimation is needed (n <= targetPoints) so callers can skip the copy.\n *\n * @param {number} n\n * @param {number} targetPoints\n * @returns {number[]|null}\n */\nexport function strideIndices(n, targetPoints) {\n if (!Number.isFinite(n) || n <= 0) return null;\n const target = Math.max(2, Math.floor(targetPoints) || 0);\n if (n <= target) return null;\n const step = (n - 1) / (target - 1);\n const idx = new Array(target);\n for (let i = 0; i < target; i++) idx[i] = Math.round(i * step);\n idx[target - 1] = n - 1; // pin the last point exactly\n // Dedupe (rounding can collide on dense targets) while staying ascending.\n let w = 0;\n for (let r = 0; r < idx.length; r++) {\n if (w === 0 || idx[r] > idx[w - 1]) idx[w++] = idx[r];\n }\n idx.length = w;\n return idx;\n}\n\n/**\n * Decimate a shared x axis plus a set of aligned series using one common\n * set of indices, so every series stays sampled at the same x (alignment-\n * and gap-safe). No-op (returns the inputs untouched) when under threshold.\n *\n * @param {Array<number>} time \u2014 shared x values\n * @param {Object<string, Array>} series \u2014 name \u2192 aligned value array\n * @param {number} targetPoints\n * @returns {{ time: Array<number>, series: Object<string, Array> }}\n */\nexport function strideDownsampleShared(time, series, targetPoints) {\n const idx = strideIndices(time?.length ?? 0, targetPoints);\n if (!idx) return { time, series };\n const dsTime = idx.map((i) => time[i]);\n const dsSeries = {};\n for (const [name, arr] of Object.entries(series || {})) {\n if (!Array.isArray(arr)) { dsSeries[name] = arr; continue; }\n dsSeries[name] = idx.map((i) => (i < arr.length ? arr[i] : null));\n }\n return { time: dsTime, series: dsSeries };\n}\n\n/**\n * Largest-Triangle-Three-Buckets for one line. Preserves the first and\n * last points and the most \"feature-bearing\" point per bucket. Assumes\n * ascending, finite x; y entries that are null/NaN are treated as 0 for\n * the area math (callers with gappy series should prefer the stride path).\n *\n * @param {Array<number>} x\n * @param {Array<number>} y\n * @param {number} threshold \u2014 target point count\n * @returns {{ x: Array<number>, y: Array<number> }}\n */\nexport function lttb(x, y, threshold) {\n const n = Math.min(x?.length ?? 0, y?.length ?? 0);\n const target = Math.floor(threshold) || 0;\n if (target <= 0 || target >= n) return { x: x.slice(0, n), y: y.slice(0, n) };\n if (target < 3) return { x: [x[0], x[n - 1]], y: [y[0], y[n - 1]] };\n\n const num = (v) => (Number.isFinite(v) ? v : 0);\n const outX = [x[0]];\n const outY = [y[0]];\n const bucketSize = (n - 2) / (target - 2);\n let a = 0;\n\n for (let i = 0; i < target - 2; i++) {\n let nextStart = Math.floor((i + 1) * bucketSize) + 1;\n let nextEnd = Math.min(Math.floor((i + 2) * bucketSize) + 1, n);\n if (nextEnd <= nextStart) nextEnd = Math.min(nextStart + 1, n);\n let avgX = 0, avgY = 0;\n const count = nextEnd - nextStart;\n for (let j = nextStart; j < nextEnd; j++) { avgX += x[j]; avgY += num(y[j]); }\n avgX /= count; avgY /= count;\n\n const curStart = Math.floor(i * bucketSize) + 1;\n const curEnd = Math.min(Math.floor((i + 1) * bucketSize) + 1, n);\n const ax = x[a], ay = num(y[a]);\n let maxArea = -1, chosen = curStart;\n for (let j = curStart; j < curEnd; j++) {\n const area = Math.abs((ax - avgX) * (num(y[j]) - ay) - (ax - x[j]) * (avgY - ay));\n if (area > maxArea) { maxArea = area; chosen = j; }\n }\n outX.push(x[chosen]); outY.push(y[chosen]);\n a = chosen;\n }\n\n outX.push(x[n - 1]); outY.push(y[n - 1]);\n return { x: outX, y: outY };\n}\n", "/**\n * plot_config.js \u2014 the shape of a plot, independent of what is being plotted.\n *\n * Subplot grid layouts, the default subplot, the legacy-format migration, and the\n * NaN strategies (gap / zero / hold / interpolate). Not one line of it knows what\n * an economy is.\n *\n * It lived in ui/js/notebook/cells/plot_cell.js \u2014 an EcoAgent notebook cell with\n * 60 domain words in it \u2014 and that single import was the only thing keeping the\n * plot windows out of @flexdesk/charts. Five modules imported these helpers THROUGH the\n * cell, which is how you end up with a chart library that depends on a notebook.\n *\n * plot_cell.js re-exports everything here, so its existing importers are unchanged.\n */\n\nimport { getSeriesColor } from './plotly_wrapper.js';\n\n\nlet _uid = 0;\nfunction uid(prefix = 'p') { return `${prefix}-${++_uid}-${Date.now().toString(36)}`; }\n\n/**\n * Apply NaN handling strategy to a data array.\n * @param {number[]} data\n * @param {'gap'|'zero'|'hold'|'interpolate'} strategy\n * @param {number[]} xData \u2014 for interpolation\n * @returns {Array}\n */\nfunction applyNanHandling(data, strategy, xData) {\n const isMissing = (v) => v === null || v === undefined || (typeof v === 'number' && !Number.isFinite(v));\n\n if (strategy === 'zero') return data.map(v => isMissing(v) ? 0 : v);\n\n if (strategy === 'hold') {\n const result = [];\n let last = null;\n for (const v of data) {\n if (isMissing(v)) result.push(last);\n else { last = v; result.push(v); }\n }\n return result;\n }\n\n if (strategy === 'interpolate') {\n const result = [...data];\n for (let i = 0; i < result.length; i++) {\n if (!isMissing(result[i])) continue;\n let left = -1, right = -1;\n for (let j = i - 1; j >= 0; j--) { if (!isMissing(result[j])) { left = j; break; } }\n for (let j = i + 1; j < result.length; j++) { if (!isMissing(result[j])) { right = j; break; } }\n if (left >= 0 && right >= 0 && xData) {\n const frac = (xData[i] - xData[left]) / (xData[right] - xData[left]);\n result[i] = result[left] + frac * (result[right] - result[left]);\n } else if (left >= 0) {\n result[i] = result[left];\n } else if (right >= 0) {\n result[i] = result[right];\n } else {\n result[i] = null;\n }\n }\n return result;\n }\n\n // 'gap' (default) \u2014 replace with null for Plotly gap rendering\n return data.map(v => isMissing(v) ? null : v);\n}\n\n// \u2500\u2500\u2500 Layout templates (matching figure_cell.js) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst PLOT_LAYOUTS = Object.freeze({\n '1x1': { label: 'Single', slots: 1, grid: { columns: '1fr', rows: '1fr' }, areas: [{ slot: 0, gridArea: '1/1/2/2' }] },\n '1x2': { label: 'Side by side', slots: 2, grid: { columns: '1fr 1fr', rows: '1fr' }, areas: [{ slot: 0, gridArea: '1/1/2/2' }, { slot: 1, gridArea: '1/2/2/3' }] },\n '2x1': { label: 'Stacked', slots: 2, grid: { columns: '1fr', rows: '1fr 1fr' }, areas: [{ slot: 0, gridArea: '1/1/2/2' }, { slot: 1, gridArea: '2/1/3/2' }] },\n '2x2': { label: '2\\u00d72 Grid', slots: 4, grid: { columns: '1fr 1fr', rows: '1fr 1fr' }, areas: [{ slot: 0, gridArea: '1/1/2/2' }, { slot: 1, gridArea: '1/2/2/3' }, { slot: 2, gridArea: '2/1/3/2' }, { slot: 3, gridArea: '2/2/3/3' }] },\n '1x3': { label: 'Three columns', slots: 3, grid: { columns: '1fr 1fr 1fr', rows: '1fr' }, areas: [{ slot: 0, gridArea: '1/1/2/2' }, { slot: 1, gridArea: '1/2/2/3' }, { slot: 2, gridArea: '1/3/2/4' }] },\n 'wide-top': { label: '1 + 2', slots: 3, grid: { columns: '1fr 1fr', rows: '1fr 1fr' }, areas: [{ slot: 0, gridArea: '1/1/2/3' }, { slot: 1, gridArea: '2/1/3/2' }, { slot: 2, gridArea: '2/2/3/3' }] },\n 'wide-bottom': { label: '2 + 1', slots: 3, grid: { columns: '1fr 1fr', rows: '1fr 1fr' }, areas: [{ slot: 0, gridArea: '1/1/2/2' }, { slot: 1, gridArea: '1/2/2/3' }, { slot: 2, gridArea: '2/1/3/3' }] },\n});\n\n/**\n * A new y axis with no series. Axis `index` 0, 2, 4, ... sits on the left,\n * 1, 3, 5, ... on the right.\n * @param {number} [index=0] - its place among the subplot's y axes\n */\nfunction makeDefaultYAxis(index = 0) {\n return {\n id: uid('y'),\n label: '',\n scale: 'linear',\n position: index % 2 === 0 ? 'left' : 'right',\n min: null,\n max: null,\n step: null,\n series: [],\n };\n}\n\n/**\n * A new series with no variable, coloured by its place in the subplot.\n * @param {number} [index=0] - how many series the subplot already has\n */\nfunction makeDefaultSeries(index = 0) {\n return {\n id: uid('s'),\n variable: '',\n label: '',\n color: getSeriesColor(index),\n lineWidth: 2,\n lineStyle: 'solid',\n stackGroup: null,\n };\n}\n\nfunction makeDefaultSubplot(index) {\n return {\n id: uid('sp'),\n displayName: '',\n chartType: 'line',\n legendPosition: 'hidden',\n interpolation: 'linear',\n nanHandling: 'gap',\n showDataPoints: false,\n xAxis: { useTime: true, variable: '' },\n zAxis: null,\n yAxes: [makeDefaultYAxis(0)],\n };\n}\n\nfunction migrateData(data) {\n // Already in multi-layout format\n if (data?.layout && Array.isArray(data?.subplots)) {\n // Migrate caption \u2192 description (old field name)\n if ('caption' in data && !('description' in data)) {\n data.description = data.caption;\n data.caption = '';\n }\n return data;\n }\n\n // Migrate legacy single-chart format \u2192 multi-layout with one subplot\n const legacySingle = migrateSingleChart(data);\n return {\n layout: '1x1',\n subplots: [{ id: uid('sp'), ...legacySingle }],\n caption: '',\n description: data?.caption ?? data?.description ?? '',\n doc: data?.doc ?? '',\n };\n}\n\n/** Migrate legacy flat series[]/variables[] to yAxes[] single-chart format. */\nfunction migrateSingleChart(data) {\n if (data?.yAxes) {\n return {\n displayName: data.displayName ?? '',\n chartType: data.chartType ?? 'line',\n legendPosition: data.legendPosition ?? 'hidden',\n interpolation: data.interpolation ?? 'linear',\n nanHandling: data.nanHandling ?? 'gap',\n showDataPoints: data.showDataPoints ?? false,\n yAxes: data.yAxes,\n };\n }\n\n const series = data?.series ?? data?.variables?.map((v, i) => ({\n variable: v, label: '', color: getSeriesColor(i),\n })) ?? [];\n\n return {\n displayName: data?.title ?? data?.displayName ?? '',\n chartType: data?.chartType ?? data?.widgetType ?? 'line',\n legendPosition: data?.legendPosition ?? 'hidden',\n interpolation: data?.interpolation ?? 'linear',\n nanHandling: data?.nanHandling ?? 'gap',\n showDataPoints: data?.showDataPoints ?? false,\n yAxes: [{\n ...makeDefaultYAxis(0),\n label: data?.yLabel ?? '',\n series: series.map((s, i) => {\n const d = makeDefaultSeries(i);\n return {\n id: s.id ?? d.id,\n variable: s.variable ?? d.variable,\n label: s.label ?? d.label,\n color: s.color ?? d.color,\n lineWidth: s.lineWidth ?? d.lineWidth,\n lineStyle: s.lineStyle ?? d.lineStyle,\n stackGroup: s.stackGroup ?? d.stackGroup,\n ...(s.overlay ? { overlay: s.overlay } : {}),\n };\n }),\n }],\n };\n}\n\nexport {\n uid, applyNanHandling, PLOT_LAYOUTS, makeDefaultSubplot, makeDefaultYAxis, makeDefaultSeries,\n migrateData, migrateSingleChart,\n};\n", "/**\n * series_transforms.js \u2014 derived series an embedder supplies: a trend, a moving\n * average, a decomposition. @flexdesk/charts ships none of its own.\n *\n * A transform is a description plus an async function:\n *\n * const seriesTransforms = {\n * movingAverage: {\n * label: 'Moving average',\n * params: { window: { label: 'Window', default: 5, min: 1, step: 1 } },\n * outputs: {\n * mean: { label: 'Mean', suffix: ' (MA)', lineStyle: 'dashed' },\n * },\n * run: async (y, params) => ({ mean: rollingMean(y, params.window) }),\n * },\n * };\n *\n * `run(y, params, context)` resolves `{ [output]: number[] }`. It is called\n * ONCE per eligible trace (a 2-D line/scatter trace) for each transform with at\n * least one output switched on, and every switched-on output it returns is\n * drawn as an extra trace in the source trace's colour, named\n * `<source name><suffix>`, with the output's `lineStyle` (solid | dashed |\n * dotted) and `lineWidth`.\n *\n * `y` is the drawn values (after the subplot's NaN handling and whatever the\n * embedder's `resolveSeries` did, such as a rebase). `context` (0.17.8) says\n * which series they are:\n *\n * { series, // the subplot's series entry the trace was drawn from\n * // (its variable, scenario, ...); null when unknown\n * subplot, // the subplot config\n * results, // the results the figure was drawn from, or null\n * resolveSeries } // the `(series, results, subplot) => { y, x? }` the\n * // figure was drawn with, or null\n *\n * so a transform can look the same series up elsewhere (a baseline scenario)\n * and resolve it the same way. renderPlotGrid (and so PlotPopoutWindow) runs\n * transforms on the same traces as before 0.17.8 (overlays included, derived\n * traces never); a trace drawn from one of the subplot's series gets that\n * series, any other (an overlay) gets `series: null`. A transform written as\n * `run(y, params)` ignores the third argument and works as before.\n *\n * A parameter is a number field by default:\n *\n * window: { label: 'Window', default: 5, min: 1, step: 1 }\n *\n * or, declared `type: 'choice'` (0.17.8), a select over `options`: an array of\n * `{ value, label }`, or a function `(subplot) => [{ value, label }]` called\n * when the controls are drawn (and when the parameter needs its default):\n *\n * baseline: { label: 'Compare with', type: 'choice',\n * options: () => scenarios.map((s) => ({ value: s.id, label: s.name })) }\n *\n * The chosen value is saved and passed to `run` like a number. Without a\n * `default` and with nothing saved, a choice is its first enabled option.\n *\n * What is switched on lives in the subplot, under `subplot.transforms`:\n *\n * subplot.transforms = { movingAverage: { outputs: { mean: true }, params: { window: 7 } } }\n *\n * A transform that throws, rejects or resolves something that is not an object\n * is skipped for that trace; the figure is drawn without it.\n */\n\nimport { buildTrace } from './chart_types.js';\nimport { flatChoices, selectBox } from '../ui/components/choice_controls.js';\n\n/** Whether a parameter spec is a choice (a select) rather than a number. */\nconst isChoice = (spec) => spec?.type === 'choice';\n\n/** A choice parameter's options for `subplot`: its array, or what its function returns. */\nfunction choiceOptions(spec, subplot) {\n const options = typeof spec.options === 'function' ? spec.options(subplot) : spec.options;\n return Array.isArray(options) ? options : [];\n}\n\n/**\n * A choice parameter's value when none is declared or saved: the option\n * selectBox selects for it, its first enabled one, `{ group, options }`\n * entries flattened in order (the first of all when every one is disabled).\n */\nfunction firstChoice(spec, subplot) {\n const flat = flatChoices(choiceOptions(spec, subplot));\n return (flat.find((o) => !o.disabled) ?? flat[0])?.value;\n}\n\n/** A transform's parameter values: its declared defaults under the subplot's own. */\nfunction resolveParams(transform, state, subplot) {\n const saved = state?.params ?? {};\n const params = {};\n for (const [name, spec] of Object.entries(transform.params ?? {})) {\n params[name] = spec?.default;\n if (isChoice(spec) && spec.default === undefined && saved[name] === undefined) {\n params[name] = firstChoice(spec, subplot);\n }\n }\n return { ...params, ...saved };\n}\n\n/** The output names of `transform` that `state` switches on, in declared order. */\nfunction enabledOutputs(transform, state) {\n return Object.keys(transform.outputs ?? {}).filter((name) => state?.outputs?.[name] === true);\n}\n\n/** A trace a transform may run on: 2-D, line or scatter, with a y array. */\nfunction isEligible(trace) {\n const type = trace.type ?? 'scatter';\n return (type === 'scatter' || type === 'scattergl') && Array.isArray(trace.y);\n}\n\n/**\n * The derived traces for one subplot's figure.\n *\n * @param {Object[]} traces - The figure's Plotly traces so far (not modified).\n * @param {Object} subplot - The subplot config; reads `subplot.transforms`.\n * @param {Object|null} seriesTransforms - `{ [id]: transform }`, or null for none.\n * @param {Object} [options]\n * @param {Function} [options.onError] - `({ transformId, traceName, error })`,\n * called for each skipped run.\n * @param {Function} [options.seriesOf] - `(trace) => series | null`: the series\n * config a trace was drawn from, passed as `context.series` (null for a\n * trace it names none for, and for every trace without it). It does not\n * choose the sources: every eligible trace is run on, as before.\n * @param {Object} [options.results] - The results the figure was drawn from\n * (`context.results`).\n * @param {Function} [options.resolveSeries] - The resolver the figure was drawn\n * with (`context.resolveSeries`).\n * @returns {Promise<Object[]>} The extra traces, in transform then trace order.\n */\nasync function deriveSeriesTraces(traces, subplot, seriesTransforms,\n { onError, seriesOf, results, resolveSeries } = {}) {\n const derived = [];\n if (!seriesTransforms) return derived;\n const sources = traces.filter(isEligible)\n .map((trace) => ({ trace, series: typeof seriesOf === 'function' ? (seriesOf(trace) ?? null) : null }));\n\n for (const [transformId, transform] of Object.entries(seriesTransforms)) {\n const state = subplot?.transforms?.[transformId];\n const outputs = enabledOutputs(transform, state);\n if (!outputs.length || typeof transform?.run !== 'function') continue;\n const params = resolveParams(transform, state, subplot);\n\n for (const { trace: source, series } of sources) {\n const context = { series, subplot, results: results ?? null, resolveSeries: resolveSeries ?? null };\n let result;\n try {\n result = await transform.run(source.y, params, context);\n } catch (error) {\n onError?.({ transformId, traceName: source.name, error });\n continue;\n }\n if (!result || typeof result !== 'object') {\n onError?.({ transformId, traceName: source.name,\n error: new Error(`transform \"${transformId}\" resolved no outputs`) });\n continue;\n }\n const color = source.line?.color || source.marker?.color;\n for (const name of outputs) {\n const y = result[name];\n if (!Array.isArray(y)) continue;\n const spec = transform.outputs[name];\n derived.push({\n ...buildTrace({\n chartType: 'line',\n x: source.x,\n y,\n name: `${source.name}${spec.suffix ?? ` (${spec.label ?? name})`}`,\n color,\n lineWidth: spec.lineWidth ?? 2,\n lineStyle: spec.lineStyle ?? 'solid',\n yAxisId: source.yaxis || 'y',\n }),\n showlegend: true,\n });\n }\n }\n }\n return derived;\n}\n\n/**\n * The controls for `seriesTransforms` in a subplot's config: per transform, a\n * toggle for each output and, for each parameter, a number field or, for a\n * `type: 'choice'` parameter, a select (choice_controls' selectBox). They edit\n * `subplot.transforms` in place and call `onChange()` after every edit. With no\n * transforms (null or `{}`) nothing is rendered.\n *\n * @param {HTMLElement} container\n * @param {Object} subplot\n * @param {Object|null} seriesTransforms\n * @param {Object} [options]\n * @param {Function} [options.onChange]\n * @returns {{ dispose: Function }}\n */\nfunction renderSeriesTransformControls(container, subplot, seriesTransforms, { onChange } = {}) {\n const entries = Object.entries(seriesTransforms ?? {});\n if (!entries.length) return { dispose() {} };\n\n const root = document.createElement('div');\n root.className = 'twm-series-transforms';\n\n const stateOf = (transformId) => {\n subplot.transforms ??= {};\n subplot.transforms[transformId] ??= {};\n return subplot.transforms[transformId];\n };\n\n for (const [transformId, transform] of entries) {\n const group = document.createElement('fieldset');\n group.className = 'twm-series-transforms__group';\n const legend = document.createElement('legend');\n legend.className = 'twm-series-transforms__label';\n legend.textContent = transform.label ?? transformId;\n group.appendChild(legend);\n\n const paramInputs = [];\n const syncDisabled = () => {\n const on = enabledOutputs(transform, subplot.transforms?.[transformId]).length > 0;\n for (const input of paramInputs) input.disabled = !on;\n };\n\n for (const [name, spec] of Object.entries(transform.outputs ?? {})) {\n const row = document.createElement('label');\n row.className = 'twm-series-transforms__row';\n const box = document.createElement('input');\n box.type = 'checkbox';\n box.checked = subplot.transforms?.[transformId]?.outputs?.[name] === true;\n box.addEventListener('change', () => {\n const state = stateOf(transformId);\n state.outputs = { ...(state.outputs ?? {}), [name]: box.checked };\n syncDisabled();\n onChange?.();\n });\n const text = document.createElement('span');\n text.textContent = spec?.label ?? name;\n row.append(box, text);\n group.appendChild(row);\n }\n\n for (const [name, spec] of Object.entries(transform.params ?? {})) {\n const row = document.createElement('label');\n row.className = 'twm-series-transforms__row';\n const text = document.createElement('span');\n text.textContent = spec?.label ?? name;\n const writeParam = (value) => {\n const state = stateOf(transformId);\n const params = { ...(state.params ?? {}) };\n if (value === undefined) delete params[name];\n else params[name] = value;\n state.params = params;\n onChange?.();\n };\n const saved = subplot.transforms?.[transformId]?.params?.[name];\n\n if (isChoice(spec)) {\n const current = saved ?? spec.default ?? firstChoice(spec, subplot);\n const choice = selectBox(choiceOptions(spec, subplot), current, {\n label: spec?.label ?? name,\n valueAttr: 'value',\n className: 'twm-series-transforms__param twm-series-transforms__select',\n });\n choice.box.addEventListener('change', () => {\n const value = choice.valueOf();\n // Redrawn with the chosen value, as settings do: a stale\n // '(not found)' entry goes once an offered option is picked.\n choice.setOptions(choiceOptions(spec, subplot), value);\n writeParam(value);\n });\n paramInputs.push(choice.box);\n row.append(text, choice.box);\n group.appendChild(row);\n continue;\n }\n\n const input = document.createElement('input');\n input.type = 'number';\n input.className = 'twm-series-transforms__param';\n for (const attr of ['min', 'max', 'step']) {\n if (spec?.[attr] != null) input[attr] = String(spec[attr]);\n }\n const current = saved ?? spec?.default;\n input.value = current == null ? '' : String(current);\n input.addEventListener('change', () => {\n const value = parseFloat(input.value);\n writeParam(Number.isFinite(value) ? value : undefined);\n });\n paramInputs.push(input);\n row.append(text, input);\n group.appendChild(row);\n }\n\n syncDisabled();\n root.appendChild(group);\n }\n\n container.appendChild(root);\n return { dispose() { root.remove(); } };\n}\n\nexport { deriveSeriesTraces, renderSeriesTransformControls };\n", "/**\n * plot_grid.js \u2014 draw a plot config into any container.\n *\n * A plot config (plot_config.js: `{ layout, subplots }`) is a grid of subplots,\n * each with one or more y-axes of series. `renderPlotGrid` lays the grid out\n * from PLOT_LAYOUTS, draws one Plotly figure per subplot and keeps them drawn:\n *\n * const grid = renderPlotGrid(el, plotConfig, { time, series }, { overlays });\n * await grid.update({ results: next }); // new data, same grid\n * grid.resize(); // after the container changed size\n * grid.dispose(); // purge every figure, remove the grid\n *\n * Per subplot it draws: the chart type, the interpolation, data points, stack\n * groups, every y-axis (left/right, linear/log, min/max/step), reference lines\n * and shaded bands, the NaN strategy, the x-axis clipped to the results' time\n * range \u2014 or an x variable instead of time (`subplot.xAxis = { useTime: false,\n * variable }`) \u2014 per-series overlay data, injected series transforms, and\n * whatever extra traces the embedder derives. A subplot with nothing to draw\n * shows the empty message; a grid slot with no subplot shows another.\n *\n * A figure is drawn only into a cell that is in the document and has a size.\n * One that is not (a hidden tab, a window not yet shown) is remembered and\n * drawn the next time the grid is resized, which its own ResizeObserver does\n * when the container gets a size.\n *\n * It was PlotPopoutWindow's private renderer; the window now calls this.\n */\n\nimport { createRafResizeObserver } from '../ui/utils/raf_resize_observer.js';\nimport { ensurePlotly } from './plotly_wrapper.js';\nimport { buildTrace, buildYAxisLayout, buildLegendLayout, buildOverlayShapes } from './chart_types.js';\nimport { PLOT_LAYOUTS, applyNanHandling } from './plot_config.js';\nimport { deriveSeriesTraces } from './series_transforms.js';\n\n/** The figure colours and font. `options.theme` overrides any of them. */\nconst PLOT_GRID_THEME = Object.freeze({\n fontFamily: 'Inter, -apple-system, BlinkMacSystemFont, sans-serif',\n fontColor: '#cccccc',\n fontSize: 11,\n paperBackground: 'transparent',\n plotBackground: 'transparent',\n gridColor: 'rgba(255,255,255,0.05)',\n lineColor: 'rgba(255,255,255,0.08)',\n tickColor: 'rgba(255,255,255,0.3)',\n zeroLineColor: 'rgba(255,255,255,0.06)',\n hoverBackground: '#1e2228',\n hoverBorder: '#444444',\n});\n\nconst OVERLAY_DASH = { dashed: 'dash', dotted: 'dot', solid: 'solid' };\n\n/**\n * The default series lookup: `results.series[series._resultKey ?? series.variable]`,\n * then `series.variable`, then the variable without its `prefix.`. Its own x is\n * `series._resultTime` when it has one.\n *\n * @param {Object} series - A series of a subplot's y-axis.\n * @param {{ time?: number[], series?: Object }} results\n * @returns {{ y: number[], x?: number[] } | null}\n */\nfunction resolveSeriesData(series, results) {\n const table = results?.series;\n const variable = series?.variable;\n if (!table || !variable) return null;\n let y = table[series._resultKey ?? variable];\n if (!y && series._resultKey) y = table[variable];\n if (!y) {\n const dot = variable.indexOf('.');\n if (dot >= 0) y = table[variable.slice(dot + 1)];\n }\n if (!y) return null;\n return series._resultTime ? { y, x: series._resultTime } : { y };\n}\n\n/**\n * The text of an empty cell: `message` itself when it is a string, else what\n * the function `message(subplot, results, index)` returns. PlotPopoutWindow\n * hands its `emptyMessage` to the grid unchanged, so this is the one place the\n * two forms are told apart.\n */\nfunction emptyMessageFor(message, subplot, results, index) {\n return typeof message === 'function' ? message(subplot, results, index) : message;\n}\n\n/**\n * Draw `plotConfig` into `container`.\n *\n * @param {HTMLElement} container - Receives one `.twm-plot-grid` child.\n * @param {{ layout: string, subplots: Object[] }} plotConfig - Already migrated (migrateData).\n * @param {{ time: number[], series: Object } | null} results - null: every subplot is empty.\n * @param {Object} [options]\n * @param {Function} [options.resolveSeries] - `(series, results, subplot) => { y, x? } | null`;\n * default resolveSeriesData. Also resolves the x variable, as `{ variable }`.\n * @param {Object} [options.overlays] - `{ [series.id]: { years, values } }`, drawn for\n * every series with an `overlay` description.\n * @param {Object} [options.seriesTransforms] - `{ [id]: transform }` (series_transforms.js).\n * Each runs on every line/scatter trace (overlays included, derived traces\n * not) as `run(y, params, { series, subplot, results, resolveSeries })`,\n * `series` being the subplot's series entry the trace was drawn from, or\n * null for an overlay.\n * @param {Function} [options.onTransformError] - `({ transformId, traceName, error })`.\n * @param {Function} [options.derivedTraces] - `(traces, subplot, { results, index })\n * => trace[] | Promise<trace[]>`: extra traces appended to a subplot's figure.\n * @param {Set<string>|string[]} [options.hiddenSeries] - Trace names not to draw.\n * @param {Object} [options.theme] - Overrides for PLOT_GRID_THEME.\n * @param {boolean} [options.alwaysShowLegend=false] - Draw a 'hidden' legend at the top.\n * @param {Object} [options.layout] - Plotly layout fields merged over every figure's.\n * @param {string|Function} [options.emptyMessage='No data yet.'] - What a subplot\n * with nothing to draw says: a string, or `(subplot, results, index) => string`,\n * called each time a cell is drawn empty (first draw, every `update()`, a\n * failed draw) with the grid's results at that moment (as the grid was given them, so null or undefined when there are none).\n * @param {string} [options.noSubplotMessage='No subplot configured.']\n * @param {Function} [options.onError] - `({ index, error })` when drawing a subplot\n * throws \u2014 on an update or on a resize that draws a deferred one; that\n * subplot shows the empty message.\n * @returns {{ update: Function, resize: Function, dispose: Function,\n * readonly charts: HTMLElement[], readonly plotted: HTMLElement[] }}\n */\nfunction renderPlotGrid(container, plotConfig, results, options = {}) {\n const opts = {\n resolveSeries: resolveSeriesData,\n overlays: null,\n seriesTransforms: null,\n onTransformError: null,\n derivedTraces: null,\n hiddenSeries: null,\n theme: null,\n alwaysShowLegend: false,\n layout: null,\n emptyMessage: 'No data yet.',\n noSubplotMessage: 'No subplot configured.',\n onError: null,\n ...options,\n };\n let config = plotConfig;\n let data = results;\n let disposed = false;\n let cells = [];\n let cellsLayout = null;\n /**\n * Per cell: the latest draw's token, from one grid-wide counter that a\n * rebuild never resets, so no draw for an old layout shares a token with a\n * draw for the new one. An older draw that resolves late is dropped.\n */\n let tokens = [];\n let lastToken = 0;\n /** Cells whose last draw found them detached or zero-size. */\n const deferred = new Set();\n\n const grid = document.createElement('div');\n grid.className = 'twm-plot-grid';\n container.appendChild(grid);\n\n const observer = createRafResizeObserver(() => resize());\n observer.observe(grid);\n\n /** Cells Plotly has been asked to draw into: every one of them is purged. */\n const plotted = new Set();\n /** Cells whose latest Plotly draw finished: they show a figure. */\n const drawn = new Set();\n const hasPlot = (cell) => plotted.has(cell);\n const purgeCell = (cell) => {\n drawn.delete(cell);\n if (!plotted.delete(cell)) return;\n try { globalThis.Plotly?.purge(cell); } catch (_) { /* already gone */ }\n };\n\n function buildCells() {\n for (const cell of cells) purgeCell(cell);\n grid.replaceChildren();\n const tmpl = PLOT_LAYOUTS[config?.layout] || PLOT_LAYOUTS['1x1'];\n grid.style.gridTemplateColumns = tmpl.grid.columns;\n grid.style.gridTemplateRows = tmpl.grid.rows;\n cells = tmpl.areas.map(({ gridArea }) => {\n const cell = document.createElement('div');\n cell.className = 'twm-plot-grid__cell';\n cell.style.gridArea = gridArea;\n grid.appendChild(cell);\n return cell;\n });\n cellsLayout = config?.layout;\n tokens = cells.map(() => 0);\n deferred.clear();\n }\n\n /** Show the empty message in cell `index`, for its subplot and the current results. */\n function showEmpty(cell, index) {\n showMessage(cell, emptyMessageFor(opts.emptyMessage, config?.subplots?.[index] ?? null, data, index));\n }\n\n function showMessage(cell, text) {\n purgeCell(cell);\n const msg = document.createElement('div');\n msg.className = 'twm-plot-no-data';\n msg.textContent = text;\n cell.replaceChildren(msg);\n }\n\n const theme = () => ({ ...PLOT_GRID_THEME, ...(opts.theme ?? {}) });\n const isHidden = (name) => {\n const h = opts.hiddenSeries;\n if (!h) return false;\n return typeof h.has === 'function' ? h.has(name) : h.includes(name);\n };\n const axisColours = (t) => ({\n gridcolor: t.gridColor, linecolor: t.lineColor,\n tickcolor: t.tickColor, zerolinecolor: t.zeroLineColor,\n });\n\n /** The traces and layout of one subplot, or null when it has nothing to draw. */\n async function buildFigure(sp, index) {\n // No results is the empty message, whatever is hidden.\n if (!data) return null;\n const t = theme();\n const time = data.time ?? [];\n const traces = [];\n const layoutAxes = {};\n const yRefByAxisId = {};\n /** The subplot's own series (overlays and derived traces aside), and how many are hidden. */\n let ownCount = 0;\n let hiddenCount = 0;\n /** Each trace drawn from one of the subplot's series, to that series (a transform's context.series). */\n const seriesByTrace = new Map();\n\n const useX = sp.xAxis && sp.xAxis.useTime === false && sp.xAxis.variable;\n const xData = useX\n ? (opts.resolveSeries({ variable: sp.xAxis.variable }, data, sp)?.y ?? time)\n : time;\n\n const yAxes = sp.yAxes ?? [];\n yAxes.forEach((axis, a) => {\n const n = a + 1;\n const yAxisKey = n === 1 ? 'yaxis' : `yaxis${n}`;\n const yRef = n === 1 ? 'y' : `y${n}`;\n if (axis.id) yRefByAxisId[axis.id] = yRef;\n\n layoutAxes[yAxisKey] = {\n ...buildYAxisLayout({\n axisId: yAxisKey,\n title: axis.label || '',\n position: axis.position || 'left',\n scaleType: axis.scale || 'linear',\n min: axis.min ?? null,\n max: axis.max ?? null,\n step: axis.step ?? null,\n showGrid: yAxes.length === 1,\n axisPosition: n > 1 ? (axis.position === 'right' ? 1 : 0) : null,\n }),\n ...axisColours(t),\n };\n\n for (const s of axis.series ?? []) {\n if (!s.variable) continue;\n const label = s.label || s.variable;\n ownCount++;\n if (isHidden(label)) { hiddenCount++; continue; }\n\n const resolved = opts.resolveSeries(s, data, sp);\n if (!resolved?.y) continue;\n const x = resolved.x ?? xData;\n const y = Array.isArray(resolved.y)\n ? applyNanHandling(resolved.y, sp.nanHandling ?? 'gap', x)\n : resolved.y;\n const trace = buildTrace({\n chartType: sp.chartType || 'line',\n x,\n y,\n name: label,\n color: s.color,\n lineWidth: s.lineWidth ?? 2,\n lineStyle: s.lineStyle ?? 'solid',\n interpolation: sp.interpolation ?? 'linear',\n yAxisId: yRef,\n showMarkers: sp.showDataPoints ?? false,\n stackGroup: s.stackGroup ?? null,\n });\n traces.push(trace);\n seriesByTrace.set(trace, s);\n\n const overlay = s.overlay ? opts.overlays?.[s.id] : null;\n if (!overlay?.years?.length) continue;\n const ov = s.overlay;\n const ovLabel = ov.label || `${label} (actual)`;\n if (isHidden(ovLabel)) continue;\n const ovTrace = {\n type: 'scatter',\n mode: ov.mode || 'markers+lines',\n x: overlay.years,\n y: overlay.values,\n name: ovLabel,\n yaxis: yRef === 'y' ? undefined : yRef,\n line: { color: ov.color || s.color, width: ov.lineWidth ?? 2,\n dash: OVERLAY_DASH[ov.lineStyle] || 'dash' },\n marker: { color: ov.color || s.color, size: 4, symbol: 'circle' },\n showlegend: true,\n };\n // A stacked-percent chart stacks its overlays too, in a group of\n // their own, so they read on the same 0..1 scale.\n if ((sp.chartType || 'line') === 'area-stacked') {\n ovTrace.stackgroup = `overlay-${yRef}`;\n ovTrace.groupnorm = 'fraction';\n ovTrace.fill = 'none';\n ovTrace.mode = 'lines';\n }\n traces.push(ovTrace);\n }\n });\n\n traces.push(...await deriveSeriesTraces(traces, sp, opts.seriesTransforms, {\n onError: opts.onTransformError ?? undefined,\n seriesOf: (trace) => seriesByTrace.get(trace) ?? null,\n results: data,\n resolveSeries: opts.resolveSeries,\n }));\n if (opts.derivedTraces) {\n const extra = await opts.derivedTraces(traces, sp, { results: data, index });\n if (Array.isArray(extra)) traces.push(...extra);\n }\n\n // Nothing to draw is the empty message \u2014 unless there are results and\n // every one of the subplot's own series is hidden: then it is an empty\n // figure, so the viewer can tell \"hidden\" from \"no data\".\n if (traces.length === 0 && !(ownCount > 0 && hiddenCount === ownCount)) return null;\n\n const legendPos = opts.alwaysShowLegend && (sp.legendPosition ?? 'hidden') === 'hidden'\n ? 'top' : (sp.legendPosition ?? 'hidden');\n const xRange = !useX && time.length >= 2 ? [time[0], time[time.length - 1]] : undefined;\n const { shapes, annotations } = buildOverlayShapes({\n referenceLines: sp.referenceLines,\n shadedBands: sp.shadedBands,\n yRefByAxisId,\n });\n const font = { family: t.fontFamily, color: t.fontColor };\n\n const layout = {\n ...layoutAxes,\n ...(shapes.length ? { shapes } : {}),\n ...(annotations.length ? { annotations } : {}),\n xaxis: {\n ...(useX ? { title: { text: sp.xAxis.label || sp.xAxis.variable, font: { size: t.fontSize } } } : {}),\n ...axisColours(t),\n automargin: true,\n ...(xRange ? { range: xRange } : {}),\n },\n ...buildLegendLayout(legendPos),\n paper_bgcolor: t.paperBackground,\n plot_bgcolor: t.plotBackground,\n font: { ...font, size: t.fontSize },\n margin: { t: 10, r: 20, b: 40, l: 50 },\n hoverlabel: { bgcolor: t.hoverBackground, bordercolor: t.hoverBorder, font },\n ...(opts.layout ?? {}),\n };\n return { traces, layout };\n }\n\n const hasSize = (cell) => cell.isConnected && cell.offsetWidth > 0 && cell.offsetHeight > 0;\n\n /** Draw cell `index`; resolves true when a figure was drawn. */\n async function drawCell(index) {\n const cell = cells[index];\n const token = ++lastToken;\n tokens[index] = token;\n const current = () => !disposed && cells[index] === cell && tokens[index] === token;\n const sp = config?.subplots?.[index];\n if (!sp) { showMessage(cell, opts.noSubplotMessage); deferred.delete(index); return false; }\n\n const figure = await buildFigure(sp, index);\n if (!current()) return false;\n if (!figure) { showEmpty(cell, index); deferred.delete(index); return false; }\n\n if (!hasSize(cell)) { deferred.add(index); return false; }\n deferred.delete(index);\n\n const Plotly = await ensurePlotly();\n if (!current()) return false;\n if (!hasPlot(cell)) cell.replaceChildren();\n plotted.add(cell);\n try {\n await Plotly.react(cell, figure.traces, figure.layout, { responsive: true, displayModeBar: false });\n if (plotted.has(cell)) drawn.add(cell);\n return true;\n } catch (_) {\n // Plotly throws when the cell is removed mid-draw.\n drawn.delete(cell);\n return false;\n }\n }\n\n /**\n * Draw cell `index` and handle a failure: a resolver, transform or\n * derivedTraces that throws costs its own subplot only \u2014 it shows the empty\n * message and is reported to onError. Every draw goes through here.\n */\n function drawCellOrFail(index) {\n const cell = cells[index];\n const pending = drawCell(index);\n const token = tokens[index];\n return pending.catch((error) => {\n if (disposed) return false;\n if (cells[index] === cell && tokens[index] === token) {\n deferred.delete(index);\n showEmpty(cell, index);\n }\n opts.onError?.({ index, error });\n return false;\n });\n }\n\n async function drawAll() {\n if (disposed) return false;\n if (cellsLayout !== config?.layout || !cells.length) buildCells();\n const results = await Promise.all(cells.map((_, i) => drawCellOrFail(i)));\n return results.some(Boolean);\n }\n\n /**\n * Change what is drawn and redraw. Every field is optional; omitted ones keep\n * their value. A config with another layout rebuilds the grid.\n *\n * @param {Object} [patch]\n * @param {Object} [patch.plotConfig]\n * @param {Object|null} [patch.results]\n * @param {Object|null} [patch.overlays]\n * @param {Set<string>|string[]|null} [patch.hiddenSeries]\n * @returns {Promise<boolean>} whether any figure was drawn\n */\n function update(patch = {}) {\n if (disposed) return Promise.resolve(false);\n if ('plotConfig' in patch) config = patch.plotConfig;\n if ('results' in patch) data = patch.results;\n if ('overlays' in patch) opts.overlays = patch.overlays;\n if ('hiddenSeries' in patch) opts.hiddenSeries = patch.hiddenSeries;\n return drawAll();\n }\n\n /** Fit every figure to its cell, and draw the ones that were waiting for a size. */\n function resize() {\n if (disposed) return;\n for (const index of [...deferred]) {\n if (!hasSize(cells[index])) continue;\n drawCellOrFail(index);\n }\n const Plotly = globalThis.Plotly;\n if (!Plotly?.Plots?.resize) return;\n for (const cell of cells) {\n if (hasPlot(cell) && hasSize(cell)) {\n Promise.resolve().then(() => Plotly.Plots.resize(cell)).catch(() => {});\n }\n }\n }\n\n /** Purge every figure and remove the grid. Later calls do nothing. */\n function dispose() {\n if (disposed) return;\n disposed = true;\n observer.disconnect();\n for (const cell of cells) purgeCell(cell);\n cells = [];\n deferred.clear();\n grid.remove();\n }\n\n drawAll();\n\n return {\n update,\n resize,\n dispose,\n /** The cells, one per grid slot, in layout order. */\n get charts() { return [...cells]; },\n /**\n * The cells that show a figure now, in layout order \u2014 however it got\n * there: an update, or a deferred draw on a resize.\n */\n get plotted() { return cells.filter((cell) => drawn.has(cell)); },\n };\n}\n\nexport { renderPlotGrid, resolveSeriesData, PLOT_GRID_THEME };\n", "/**\n * Plot Popout Window\n *\n * Opens a plot in a separate draggable/resizable ManagedWindow with two tabs:\n * - Plot tab: Interactive Plotly chart grid with modebar controls\n * - Data tab: Table showing all series using the unified DataTable component\n *\n * Uses the PlotCell data model (multi-layout subplots) as its canonical format.\n * All plot window contexts (notebook, dashboard, documentation) use this single\n * implementation.\n *\n * Features:\n * - Multi-subplot grid layouts (1x1, 1x2, 2x1, 2x2, 1x3, wide-top, wide-bottom)\n * - Series visibility toggle panel\n * - Zoom/pan toolbar with zoom in/out, autoscale, reset\n * - CSV and PNG export through the host's dialogs (else a browser download)\n * - NotificationCenter integration for user feedback\n * - Live streaming updates while the data source is running\n * - Derived series from injected transforms (`seriesTransforms`)\n * - ETL actuals overlay support\n *\n * The figures are drawn by renderPlotGrid (plot_grid.js); this window adds the\n * tabs, the toolbar, the series toggles and the data table around them.\n */\n\nimport { ManagedWindow } from '../ui/components/managed_window.js';\nimport { DataTable } from '../ui/components/data_table.js';\nimport { createRafResizeObserver } from '../ui/utils/raf_resize_observer.js';\nimport {\n ensurePlotly,\n purge,\n getSeriesColor,\n} from './plotly_wrapper.js';\nimport { migrateData } from './plot_config.js';\nimport { renderPlotGrid, resolveSeriesData } from './plot_grid.js';\n\nexport class PlotPopoutWindow {\n /**\n * @param {Object} options\n * @param {string} options.id - Unique window identifier\n * @param {string} options.title - Window title\n * @param {Object} options.plotConfig - PlotCell format: { layout, subplots }\n * @param {Function} options.getResults - Returns { time: number[], series: { [key]: number[] } }\n * @param {Object} options.services - { eventBus, logger }\n * @param {Object} [options.host] - A Host (ui/js/host/host.js). Its `dialogs`\n * capability backs Export PNG/CSV; absent => Blob download fallback.\n * @param {Function} [options.onClose] - Called when window closes\n * @param {Object} [options.actuals] - ETL overlay data { seriesId: { years, values } }\n * @param {Function} [options.configRenderer] - `(container) => { dispose() } | void` \u2014\n * renders the Config tab. What it returns is disposed (`dispose()`) when the\n * window closes, so an editor drawn there (renderPlotConfigEditor) goes with it.\n * @param {Object} [options.seriesTransforms] - `{ [id]: transform }` (series_transforms.js);\n * absent => no derived series are drawn. Each runs as\n * `run(y, params, { series, subplot, results, resolveSeries })` (renderPlotGrid).\n * @param {string} [options.refreshEvent='data:changed'] - Bus event after which the\n * window re-reads `getResults()` and redraws.\n * @param {{delta?: string|null, complete?: string|null}} [options.streamEvents] - Bus\n * events a live data source emits while it runs (`delta`) and when it ends\n * (`complete`); the window redraws on each while live update is on.\n * There are no default names: without `streamEvents` (or with a name\n * left out or given as null) nothing is listened for, and the window\n * updates through `refreshEvent` and explicit calls only.\n * @param {Function} [options.resolveSeries] - `(series, results, subplot) => { y, x? } | null`\n * (plot_grid.js); used by the chart and the data table. Default resolveSeriesData.\n * @param {string|Function} [options.emptyMessage='No data yet.'] - What a chart\n * cell with nothing to draw says: a string, or `(subplot, results, index) =>\n * string`, called on every redraw that leaves the cell empty (renderPlotGrid).\n * @param {string} [options.tableEmptyMessage='No data yet.'] - What the Data tab\n * says with no rows.\n */\n constructor({ id, title, plotConfig, getResults, services, host, onClose, actuals,\n configRenderer, seriesTransforms, resolveSeries = resolveSeriesData,\n // The window used to listen for 'simulation:run:completed' and tell\n // the user to \"run simulation first\". A chart window does not know\n // that its data comes from a simulation; the app that opens it does.\n refreshEvent = 'data:changed',\n streamEvents = {},\n emptyMessage = 'No data yet.',\n tableEmptyMessage = 'No data yet.' }) {\n this._id = id;\n this._title = title || 'Plot';\n this._plotConfig = migrateData(plotConfig);\n this._getResults = getResults;\n this._services = services;\n this._host = host || null;\n this._onClose = onClose ?? (() => {});\n this._actuals = actuals ?? null;\n this._configRenderer = configRenderer ?? null;\n this._seriesTransforms = seriesTransforms ?? null;\n this._resolveSeries = resolveSeries;\n this.refreshEvent = refreshEvent;\n this.streamEvents = Object.freeze({ delta: streamEvents?.delta ?? null,\n complete: streamEvents?.complete ?? null });\n // TWO messages, not one. The chart says \"No data \u2014 run simulation first.\"\n // and the data table underneath says \"Run simulation to see data\". Folding\n // them into a single option would have quietly rewritten one of them, which\n // is the kind of change a pixel gate catches only if a captured view happens\n // to be showing an empty plot.\n this.emptyMessage = emptyMessage;\n this.tableEmptyMessage = tableEmptyMessage;\n\n this._window = null;\n this._contentEl = null;\n this._grid = null;\n this._gridEl = null;\n this._activeTab = 'plot';\n this._eventDisposers = [];\n this._lastResults = null;\n\n // Data table\n this._dataTable = null;\n this._dataTableContainer = null;\n this._tableHeaders = [];\n this._tableRows = [];\n\n // DOM refs\n this._plotTab = null;\n this._dataTab = null;\n this._configTab = null;\n this._plotContent = null;\n this._dataContent = null;\n this._configContent = null;\n this._configHandle = null;\n this._toolbarActions = null;\n this._zoomBtn = null;\n this._panBtn = null;\n\n // Series visibility toggle\n this._hiddenSeries = new Set();\n this._allSeriesInfo = [];\n this._allSeriesLabels = [];\n this._seriesToggleBtn = null;\n this._seriesTogglePanel = null;\n this._seriesTogglePanelVisible = false;\n this._lastTogglePanelSignature = null;\n this._outsideClickHandler = null;\n\n this._renderPending = false;\n /** updateConfig() ran since the last #render(); applied even without results. */\n this._configChanged = false;\n\n // Live-update toggle: when true, window re-renders on streaming events\n this._liveUpdate = true;\n this._liveBtn = null;\n }\n\n get isVisible() { return this._window?.isVisible ?? false; }\n\n async show() {\n if (this._window?.isVisible) {\n this._window.bringToFront();\n return;\n }\n\n await ensurePlotly();\n this.#createWindow();\n this.#subscribeEvents();\n await this.#render();\n }\n\n bringToFront() { this._window?.bringToFront?.(); }\n\n close() { this._window?.close?.(); }\n\n /** Update plot config and re-render. */\n updateConfig(plotConfig) {\n this._plotConfig = migrateData(plotConfig);\n this._configChanged = true;\n this.#scheduleRender();\n }\n\n /** Update actuals overlay data and re-render. */\n setActuals(actuals) {\n this._actuals = actuals;\n this.#scheduleRender();\n }\n\n // \u2500\u2500 Window creation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n #createWindow() {\n this._contentEl = this.#buildContent();\n\n this._window = new ManagedWindow({\n id: `plot-window-${this._id}`,\n title: this._title,\n icon: 'monitoring',\n content: this._contentEl,\n minWidth: 500,\n minHeight: 400,\n defaultWidth: 800,\n defaultHeight: 600,\n canMinimize: true,\n canMaximize: true,\n canResize: true,\n canDrag: true,\n onClose: () => { this.#dispose(); this._onClose(); },\n });\n\n this._window.show();\n }\n\n #buildContent() {\n const container = document.createElement('div');\n container.className = 'twm-plot-window-container';\n\n // Tab header\n const tabHeader = document.createElement('div');\n tabHeader.className = 'twm-code-tabs-header';\n\n const tabs = document.createElement('div');\n tabs.className = 'tabs twm-code-tabs';\n\n this._plotTab = document.createElement('button');\n this._plotTab.className = 'twm-code-tab active';\n this._plotTab.type = 'button';\n this._plotTab.textContent = 'Plot';\n this._plotTab.addEventListener('click', () => this.#switchTab('plot'));\n\n this._dataTab = document.createElement('button');\n this._dataTab.className = 'twm-code-tab';\n this._dataTab.type = 'button';\n this._dataTab.textContent = 'Data';\n this._dataTab.addEventListener('click', () => this.#switchTab('data'));\n\n tabs.appendChild(this._plotTab);\n tabs.appendChild(this._dataTab);\n\n if (this._configRenderer) {\n this._configTab = document.createElement('button');\n this._configTab.className = 'twm-code-tab';\n this._configTab.type = 'button';\n this._configTab.textContent = 'Config';\n this._configTab.addEventListener('click', () => this.#switchTab('config'));\n tabs.appendChild(this._configTab);\n }\n\n // Toolbar (visible when Plot tab is active)\n this._toolbarActions = document.createElement('div');\n this._toolbarActions.className = 'twm-plot-window-toolbar';\n\n // Drag mode group\n const dragGroup = this.#toolbarGroup();\n this._zoomBtn = this.#toolbarBtn('search', 'Zoom', () => this.#setDragMode('zoom'));\n this._zoomBtn.classList.add('twm-is-active');\n this._panBtn = this.#toolbarBtn('pan_tool', 'Pan', () => this.#setDragMode('pan'));\n dragGroup.appendChild(this._zoomBtn);\n dragGroup.appendChild(this._panBtn);\n this._toolbarActions.appendChild(dragGroup);\n\n // Zoom control group\n const zoomGroup = this.#toolbarGroup();\n zoomGroup.appendChild(this.#toolbarBtn('zoom_in', 'Zoom in', () => this.#zoom(0.5)));\n zoomGroup.appendChild(this.#toolbarBtn('zoom_out', 'Zoom out', () => this.#zoom(2)));\n zoomGroup.appendChild(this.#toolbarBtn('zoom_out_map', 'Autoscale', () => this.#autoscale()));\n zoomGroup.appendChild(this.#toolbarBtn('home', 'Reset axes', () => this.#autoscale()));\n this._toolbarActions.appendChild(zoomGroup);\n\n // Spacer\n const spacer = document.createElement('div');\n spacer.style.flex = '1';\n this._toolbarActions.appendChild(spacer);\n\n // Action buttons group\n const actionsGroup = this.#toolbarGroup();\n\n // Live-update toggle\n this._liveBtn = this.#toolbarBtn('stream', 'Live update \u2014 click to lock', () => this.#toggleLiveUpdate());\n this._liveBtn.classList.add('twm-is-active');\n actionsGroup.appendChild(this._liveBtn);\n\n // Series visibility toggle\n const toggleSeriesBtn = this.#toolbarBtn('visibility', 'Toggle series visibility', () => this.#toggleSeriesPanel());\n this._seriesToggleBtn = toggleSeriesBtn;\n actionsGroup.appendChild(toggleSeriesBtn);\n\n // Download PNG\n actionsGroup.appendChild(this.#toolbarBtn('image', 'Download plot as PNG', () => this.#downloadPNG()));\n\n // Download CSV\n actionsGroup.appendChild(this.#toolbarBtn('download', 'Download data as CSV', () => this.#downloadCSV()));\n\n this._toolbarActions.appendChild(actionsGroup);\n\n tabHeader.appendChild(tabs);\n tabHeader.appendChild(this._toolbarActions);\n\n // Tab content area\n const content = document.createElement('div');\n content.className = 'twm-plot-window-content';\n\n // Plot tab content\n this._plotContent = document.createElement('div');\n this._plotContent.className = 'twm-plot-tab-content active';\n this._plotContent.setAttribute('data-tab', 'plot');\n this._plotContent.style.cssText = 'display:flex; flex-direction:column;';\n\n this._gridEl = document.createElement('div');\n this._gridEl.className = 'twm-plot-window-chart';\n this._plotContent.appendChild(this._gridEl);\n\n this._grid = renderPlotGrid(this._gridEl, this._plotConfig, null, {\n resolveSeries: this._resolveSeries,\n overlays: this._actuals,\n hiddenSeries: this._hiddenSeries,\n seriesTransforms: this._seriesTransforms,\n onTransformError: ({ transformId, traceName, error }) => this._services?.logger?.warn?.(\n `[PlotPopoutWindow] transform \"${transformId}\" failed on \"${traceName}\"`, error),\n // Popout windows have space \u2014 always show the legend.\n alwaysShowLegend: true,\n layout: { autosize: true, hovermode: 'x unified' },\n emptyMessage: this.emptyMessage,\n onError: ({ index, error }) => this._services?.logger?.warn?.(\n `[PlotPopoutWindow] subplot ${index + 1} failed to draw`, error),\n });\n\n // Data tab content\n this._dataContent = document.createElement('div');\n this._dataContent.className = 'twm-plot-tab-content';\n this._dataContent.setAttribute('data-tab', 'data');\n this._dataContent.style.cssText = 'display:none; flex-direction:column;';\n\n this._dataTableContainer = document.createElement('div');\n this._dataTableContainer.style.cssText = 'flex:1; min-height:0; display:flex; flex-direction:column;';\n this._dataContent.appendChild(this._dataTableContainer);\n\n content.appendChild(this._plotContent);\n content.appendChild(this._dataContent);\n\n // Config tab content (optional)\n if (this._configRenderer) {\n this._configContent = document.createElement('div');\n this._configContent.className = 'twm-plot-tab-content';\n this._configContent.setAttribute('data-tab', 'config');\n this._configContent.style.cssText = 'display:none; flex-direction:column; overflow:auto; padding:8px 12px;';\n this._configHandle = this._configRenderer(this._configContent) ?? null;\n content.appendChild(this._configContent);\n }\n\n // Series visibility dropdown panel (initially hidden)\n this._seriesTogglePanel = document.createElement('div');\n this._seriesTogglePanel.className = 'twm-plot-series-toggle-panel';\n this._seriesTogglePanel.style.display = 'none';\n\n container.appendChild(tabHeader);\n container.appendChild(content);\n container.appendChild(this._seriesTogglePanel);\n\n return container;\n }\n\n // \u2500\u2500 Toolbar helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n #toolbarGroup() {\n const g = document.createElement('div');\n g.className = 'twm-plot-window-toolbar__group';\n return g;\n }\n\n #toolbarBtn(icon, tooltip, onClick) {\n const btn = document.createElement('button');\n btn.className = 'twm-btn-icon twm-has-tooltip';\n btn.type = 'button';\n btn.setAttribute('data-tooltip', tooltip);\n btn.innerHTML = `<span class=\"material-symbols-outlined\">${icon}</span>`;\n if (onClick) btn.addEventListener('click', (e) => { e.stopPropagation(); onClick(); });\n return btn;\n }\n\n // \u2500\u2500 Plotly toolbar actions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n get #charts() { return this._grid?.charts ?? []; }\n /** The subplots that show a figure \u2014 the grid knows, however it drew them. */\n get #plottedCharts() { return this._grid?.plotted ?? []; }\n\n #setDragMode(mode) {\n if (!this.#plottedCharts.length) return;\n for (const div of this.#charts) {\n if (div._fullLayout) {\n window.Plotly.relayout(div, { dragmode: mode }).catch(() => {});\n }\n }\n this._zoomBtn?.classList.toggle('twm-is-active', mode === 'zoom');\n this._panBtn?.classList.toggle('twm-is-active', mode === 'pan');\n }\n\n #zoom(factor) {\n for (const div of this.#charts) {\n if (!div._fullLayout) continue;\n const xa = div._fullLayout.xaxis;\n const ya = div._fullLayout.yaxis;\n if (!xa || !ya) continue;\n\n const xr = xa.range;\n const yr = ya.range;\n const xMid = (xr[0] + xr[1]) / 2;\n const yMid = (yr[0] + yr[1]) / 2;\n const xHalf = (xr[1] - xr[0]) / 2 * factor;\n const yHalf = (yr[1] - yr[0]) / 2 * factor;\n\n window.Plotly.relayout(div, {\n 'xaxis.range': [xMid - xHalf, xMid + xHalf],\n 'yaxis.range': [yMid - yHalf, yMid + yHalf],\n }).catch(() => {});\n }\n }\n\n #autoscale() {\n for (const div of this.#charts) {\n if (!div._fullLayout) continue;\n window.Plotly.relayout(div, {\n 'xaxis.autorange': true,\n 'yaxis.autorange': true,\n }).catch(() => {});\n }\n }\n\n #switchTab(tabName) {\n this._activeTab = tabName;\n\n this._plotTab.classList.toggle('active', tabName === 'plot');\n this._dataTab.classList.toggle('active', tabName === 'data');\n this._configTab?.classList.toggle('active', tabName === 'config');\n\n if (this._toolbarActions) {\n this._toolbarActions.style.display = tabName === 'plot' ? '' : 'none';\n }\n\n this._plotContent.style.display = tabName === 'plot' ? 'flex' : 'none';\n this._dataContent.style.display = tabName === 'data' ? 'flex' : 'none';\n if (this._configContent) {\n this._configContent.style.display = tabName === 'config' ? 'flex' : 'none';\n }\n\n if (tabName === 'plot') this._grid?.resize();\n\n if (tabName === 'data') {\n this.#renderDataTable();\n }\n }\n\n // \u2500\u2500 Series visibility toggle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n #toggleSeriesPanel() {\n if (this._seriesTogglePanelVisible) {\n this.#hideSeriesPanel();\n } else {\n this.#showSeriesPanel();\n }\n }\n\n #showSeriesPanel() {\n if (!this._seriesTogglePanel || !this._seriesToggleBtn) return;\n\n const btnRect = this._seriesToggleBtn.getBoundingClientRect();\n const containerRect = this._contentEl.getBoundingClientRect();\n\n this._seriesTogglePanel.style.top = `${btnRect.bottom - containerRect.top + 4}px`;\n this._seriesTogglePanel.style.right = `${containerRect.right - btnRect.right}px`;\n this._seriesTogglePanel.style.display = '';\n this._seriesTogglePanelVisible = true;\n\n this._seriesToggleBtn.classList.add('twm-is-active');\n this.#rebuildSeriesToggleList();\n\n this._outsideClickHandler = (e) => {\n if (!this._seriesTogglePanel.contains(e.target) &&\n !this._seriesToggleBtn.contains(e.target)) {\n this.#hideSeriesPanel();\n }\n };\n requestAnimationFrame(() => {\n document.addEventListener('pointerdown', this._outsideClickHandler, true);\n });\n }\n\n #hideSeriesPanel() {\n if (this._seriesTogglePanel) {\n this._seriesTogglePanel.style.display = 'none';\n }\n this._seriesTogglePanelVisible = false;\n this._lastTogglePanelSignature = null;\n this._seriesToggleBtn?.classList.remove('twm-is-active');\n\n if (this._outsideClickHandler) {\n document.removeEventListener('pointerdown', this._outsideClickHandler, true);\n this._outsideClickHandler = null;\n }\n }\n\n #rebuildSeriesToggleList() {\n const panel = this._seriesTogglePanel;\n if (!panel) return;\n panel.innerHTML = '';\n\n // Header with \"All\" / \"None\" actions\n const header = document.createElement('div');\n header.className = 'twm-plot-series-toggle-panel__header';\n\n const title = document.createElement('span');\n title.className = 'twm-plot-series-toggle-panel__title';\n title.textContent = 'Series';\n header.appendChild(title);\n\n const headerActions = document.createElement('div');\n headerActions.className = 'twm-plot-series-toggle-panel__header-actions';\n\n const showAllBtn = document.createElement('button');\n showAllBtn.className = 'twm-plot-series-toggle-panel__action';\n showAllBtn.type = 'button';\n showAllBtn.textContent = 'All';\n showAllBtn.addEventListener('click', () => {\n this._hiddenSeries.clear();\n this.#rebuildSeriesToggleList();\n this.#scheduleRender();\n });\n\n const hideAllBtn = document.createElement('button');\n hideAllBtn.className = 'twm-plot-series-toggle-panel__action';\n hideAllBtn.type = 'button';\n hideAllBtn.textContent = 'None';\n hideAllBtn.addEventListener('click', () => {\n for (const label of this._allSeriesLabels) {\n this._hiddenSeries.add(label);\n }\n this.#rebuildSeriesToggleList();\n this.#scheduleRender();\n });\n\n headerActions.appendChild(showAllBtn);\n headerActions.appendChild(hideAllBtn);\n header.appendChild(headerActions);\n panel.appendChild(header);\n\n // Split series into model vs overlay\n const modelSeries = this._allSeriesInfo.filter(s => !s.isOverlay);\n const overlaySeries = this._allSeriesInfo.filter(s => s.isOverlay);\n\n const buildItem = ({ label, color, lineStyle }) => {\n const item = document.createElement('label');\n item.className = 'twm-plot-series-toggle-panel__item';\n\n const cb = document.createElement('input');\n cb.type = 'checkbox';\n cb.checked = !this._hiddenSeries.has(label);\n cb.addEventListener('change', () => {\n if (cb.checked) this._hiddenSeries.delete(label);\n else this._hiddenSeries.add(label);\n this.#scheduleRender();\n });\n\n const dashMap = { solid: '', dashed: '4,2', dotted: '1,2' };\n const indicator = document.createElement('div');\n indicator.className = 'twm-plot-series-toggle-panel__line-indicator';\n const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');\n svg.setAttribute('viewBox', '0 0 28 14');\n const line = document.createElementNS('http://www.w3.org/2000/svg', 'line');\n line.setAttribute('x1', '3');\n line.setAttribute('y1', '7');\n line.setAttribute('x2', '25');\n line.setAttribute('y2', '7');\n line.setAttribute('stroke', color || '#888');\n line.setAttribute('stroke-width', '2');\n line.setAttribute('stroke-linecap', 'round');\n const dash = dashMap[lineStyle] || '';\n if (dash) line.setAttribute('stroke-dasharray', dash);\n svg.appendChild(line);\n indicator.appendChild(svg);\n\n const text = document.createElement('span');\n text.className = 'twm-plot-series-toggle-panel__label';\n text.textContent = label;\n text.title = label;\n\n item.appendChild(cb);\n item.appendChild(indicator);\n item.appendChild(text);\n return item;\n };\n\n // Model series section\n const list = document.createElement('div');\n list.className = 'twm-plot-series-toggle-panel__list';\n\n const subplotGroups = new Map();\n for (const info of modelSeries) {\n if (!subplotGroups.has(info.subplotIndex)) {\n subplotGroups.set(info.subplotIndex, []);\n }\n subplotGroups.get(info.subplotIndex).push(info);\n }\n\n const multipleSubplots = subplotGroups.size > 1;\n\n for (const [spIdx, seriesList] of subplotGroups) {\n if (multipleSubplots) {\n const spName = seriesList[0]?.subplotName || `Subplot ${spIdx + 1}`;\n const spHeader = document.createElement('div');\n spHeader.className = 'twm-plot-series-toggle-panel__axis-label';\n spHeader.textContent = spName;\n list.appendChild(spHeader);\n }\n\n for (const info of seriesList) {\n list.appendChild(buildItem(info));\n }\n }\n\n panel.appendChild(list);\n\n // Overlays section (only if any exist)\n if (overlaySeries.length > 0) {\n const ovList = document.createElement('div');\n ovList.className = 'twm-plot-series-toggle-panel__list';\n\n const ovHeader = document.createElement('div');\n ovHeader.className = 'twm-plot-series-toggle-panel__axis-label';\n ovHeader.textContent = 'Overlays';\n ovList.appendChild(ovHeader);\n\n for (const info of overlaySeries) {\n ovList.appendChild(buildItem(info));\n }\n\n panel.appendChild(ovList);\n }\n }\n\n // \u2500\u2500 Event subscriptions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n #subscribeEvents() {\n const { eventBus } = this._services;\n if (!eventBus) return;\n\n const { delta, complete } = this.streamEvents;\n for (const name of new Set([delta, complete])) {\n if (!name) continue;\n this._eventDisposers.push(\n eventBus.on(name, () => {\n if (this._liveUpdate) this.#scheduleRender();\n })\n );\n }\n // Final analytics arrive asynchronously after the stream's complete event\n // (backend fetch + transform). Without this, the popout window may\n // render stale data from a previous run when the dashboard tab\n // didn't receive streaming deltas (e.g. user was on another tab).\n this._eventDisposers.push(\n eventBus.on(this.refreshEvent, () => {\n if (this._liveUpdate) this.#scheduleRender();\n })\n );\n }\n\n #toggleLiveUpdate() {\n this._liveUpdate = !this._liveUpdate;\n if (this._liveBtn) {\n this._liveBtn.classList.toggle('twm-is-active', this._liveUpdate);\n const icon = this._liveBtn.querySelector('.material-symbols-outlined');\n if (icon) icon.textContent = this._liveUpdate ? 'stream' : 'lock';\n this._liveBtn.title = this._liveUpdate\n ? 'Live update \u2014 click to lock'\n : 'Locked \u2014 click for live update';\n }\n // If switching back to live, immediately render latest data\n if (this._liveUpdate) this.#scheduleRender();\n }\n\n #scheduleRender() {\n if (this._renderPending) return;\n this._renderPending = true;\n requestAnimationFrame(() => {\n this._renderPending = false;\n this.#render();\n });\n }\n\n // \u2500\u2500 Rendering \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async #render() {\n if (!this._window?.isVisible) return;\n\n const results = this._getResults?.();\n const configChanged = this._configChanged;\n this._configChanged = false;\n if (!results) {\n // No data yet: the figures already drawn stay, unless the layout or\n // the subplots changed, in which case the grid is rebuilt for them.\n if (configChanged) {\n await this._grid.update({\n plotConfig: this._plotConfig,\n results: null,\n overlays: this._actuals,\n hiddenSeries: this._hiddenSeries,\n });\n }\n return;\n }\n\n this._lastResults = results;\n\n // Build series info for toggle panel\n this.#collectSeriesInfo();\n\n // Render all subplot charts\n await this._grid.update({\n plotConfig: this._plotConfig,\n results,\n overlays: this._actuals,\n hiddenSeries: this._hiddenSeries,\n });\n if (!this._window) return;\n\n // Update table data\n this.#updateTableData(results);\n\n if (this._activeTab === 'data') {\n this.#renderDataTable();\n }\n }\n\n #collectSeriesInfo() {\n this._allSeriesInfo = [];\n this._allSeriesLabels = [];\n\n const subplots = this._plotConfig.subplots ?? [];\n for (let spIdx = 0; spIdx < subplots.length; spIdx++) {\n const sp = subplots[spIdx];\n for (const axis of sp.yAxes ?? []) {\n for (const s of axis.series ?? []) {\n const label = s.label || s.variable || 'Series';\n this._allSeriesInfo.push({\n label,\n color: s.color || getSeriesColor(this._allSeriesInfo.length),\n lineStyle: s.lineStyle || 'solid',\n subplotIndex: spIdx,\n subplotName: sp.displayName || `Subplot ${spIdx + 1}`,\n });\n this._allSeriesLabels.push(label);\n\n // Include overlay in toggle list\n if (s.overlay) {\n const ovLabel = s.overlay.label || `${label} (actual)`;\n this._allSeriesInfo.push({\n label: ovLabel,\n color: s.overlay.color || s.color || getSeriesColor(this._allSeriesInfo.length),\n lineStyle: s.overlay.lineStyle || 'dashed',\n subplotIndex: spIdx,\n subplotName: sp.displayName || `Subplot ${spIdx + 1}`,\n isOverlay: true,\n });\n this._allSeriesLabels.push(ovLabel);\n }\n }\n }\n }\n\n // Prune hidden labels that no longer exist\n for (const label of this._hiddenSeries) {\n if (!this._allSeriesLabels.includes(label)) {\n this._hiddenSeries.delete(label);\n }\n }\n\n // Update toggle panel if visible\n if (this._seriesTogglePanelVisible) {\n const newSig = this._allSeriesInfo.map(s => `${s.subplotIndex}|${s.label}|${s.lineStyle}`).join('\\x00');\n if (newSig !== this._lastTogglePanelSignature) {\n this._lastTogglePanelSignature = newSig;\n this.#rebuildSeriesToggleList();\n }\n }\n\n // Update toggle button icon\n if (this._seriesToggleBtn) {\n const icon = this._seriesToggleBtn.querySelector('.material-symbols-outlined');\n if (icon) {\n icon.textContent = this._hiddenSeries.size > 0 ? 'visibility_off' : 'visibility';\n }\n }\n }\n\n // \u2500\u2500 Data table \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n #updateTableData(results) {\n if (!results) {\n this._tableHeaders = [];\n this._tableRows = [];\n return;\n }\n\n const headers = ['Time'];\n const seriesColumns = [];\n const { time } = results;\n const subplots = this._plotConfig.subplots ?? [];\n\n for (const sp of subplots) {\n for (const axis of sp.yAxes ?? []) {\n for (const s of axis.series ?? []) {\n if (!s.variable) continue;\n const label = s.label || s.variable;\n const rawY = this._resolveSeries(s, results, sp)?.y;\n if (!rawY) continue;\n headers.push(label);\n seriesColumns.push(rawY);\n }\n }\n }\n\n const rows = [];\n for (let i = 0; i < time.length; i++) {\n const row = [time[i]];\n for (const col of seriesColumns) {\n row.push(Array.isArray(col) ? col[i] : null);\n }\n rows.push(row);\n }\n\n this._tableHeaders = headers;\n this._tableRows = rows;\n }\n\n #renderDataTable() {\n if (!this._dataTableContainer) return;\n\n if (!this._dataTable) {\n this._dataTable = new DataTable(this._dataTableContainer, {\n headers: this._tableHeaders,\n rows: this._tableRows,\n pageSize: 100,\n pagination: true,\n selectable: true,\n copyable: true,\n sortable: true,\n filterable: true,\n readonly: false,\n emptyMessage: this.tableEmptyMessage,\n services: this._services,\n host: this._host,\n });\n this._dataTable.render();\n } else {\n this._dataTable.setData({\n headers: this._tableHeaders,\n rows: this._tableRows,\n });\n }\n }\n\n // \u2500\u2500 Downloads \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n async #downloadCSV() {\n if (this._tableRows.length === 0) {\n this.#notify('Download', 'No data available to download.', 'warn');\n return;\n }\n\n const filename = `${this._title.replace(/[^a-z0-9]/gi, '_')}_data.csv`;\n\n const lines = [this._tableHeaders.join(',')];\n for (const row of this._tableRows) {\n lines.push(row.map(val => this.#csvEscape(val)).join(','));\n }\n const csv = lines.join('\\n');\n\n // null <=> the host has no save dialog behind its `dialogs` capability\n // (host.js). Fall back; do not report it as a failed save.\n const dialogs = this._host?.dialogs;\n let result = null;\n if (dialogs) {\n try {\n result = await dialogs.saveFile({ data: csv, filename, kind: 'csv' });\n } catch (err) {\n console.error('[PlotPopoutWindow] CSV download failed:', err);\n this.#notify('Download', 'Failed to save file', 'error');\n return;\n }\n }\n if (result) {\n if (result.ok) {\n this.#notify('Download', `Saved ${this._tableRows.length} rows to ${result.path}`, 'success');\n } else if (!result.cancelled) {\n this.#notify('Download', result.error || 'Failed to save file', 'error');\n }\n return;\n }\n\n const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n link.click();\n URL.revokeObjectURL(url);\n this.#notify('Download', 'Download started', 'info');\n }\n\n #csvEscape(value) {\n if (value == null) return '';\n const str = String(value);\n if (str.includes(',') || str.includes('\"') || str.includes('\\n')) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`;\n }\n return str;\n }\n\n async #downloadPNG() {\n // The first subplot that shows a figure.\n const targetDiv = this.#plottedCharts[0];\n if (!targetDiv || !window.Plotly) {\n this.#notify('Download', 'Plot not ready', 'warn');\n return;\n }\n\n const filename = `${this._title.replace(/[^a-z0-9]/gi, '_')}.png`;\n\n try {\n const pngDataUrl = await window.Plotly.toImage(targetDiv, {\n format: 'png',\n width: 1920,\n height: 1080,\n scale: 2,\n });\n\n // null <=> no save dialog behind the capability (host.js) -> fall back.\n const dialogs = this._host?.dialogs;\n const result = dialogs\n ? await dialogs.saveFile({ data: pngDataUrl.split(',')[1], filename, kind: 'png' })\n : null;\n if (result) {\n if (result.ok) {\n this.#notify('Download', `Plot saved to ${result.path}`, 'success');\n } else if (!result.cancelled) {\n this.#notify('Download', result.error || 'Failed to save image', 'error');\n }\n } else {\n const link = document.createElement('a');\n link.href = pngDataUrl;\n link.download = filename;\n link.click();\n this.#notify('Download', 'PNG download started', 'info');\n }\n } catch (err) {\n this._services.logger?.warn?.('[PlotPopoutWindow] PNG download failed', err);\n this.#notify('Download', 'Failed to generate PNG', 'error');\n }\n }\n\n // \u2500\u2500 Utilities \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n #notify(title, message, severity = 'info') {\n this._services.eventBus?.emit?.('toast:show', {\n title,\n message,\n type: severity,\n });\n }\n\n // \u2500\u2500 Cleanup \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n #dispose() {\n if (this._dataTable) {\n this._dataTable.dispose();\n this._dataTable = null;\n }\n\n this.#hideSeriesPanel();\n\n for (const disposer of this._eventDisposers) {\n try { disposer?.dispose?.(); } catch (_) {}\n }\n this._eventDisposers = [];\n\n // What configRenderer returned (an editor with dropdowns in document.body,\n // say) goes with the window.\n try { this._configHandle?.dispose?.(); } catch (error) {\n this._services?.logger?.warn?.('[PlotPopoutWindow] the config panel failed to dispose', error);\n }\n this._configHandle = null;\n\n this._grid?.dispose();\n this._grid = null;\n\n this._window = null;\n this._contentEl = null;\n this._gridEl = null;\n this._plotTab = null;\n this._dataTab = null;\n this._plotContent = null;\n this._dataContent = null;\n this._dataTableContainer = null;\n this._toolbarActions = null;\n this._zoomBtn = null;\n this._panBtn = null;\n this._seriesToggleBtn = null;\n this._seriesTogglePanel = null;\n this._lastTogglePanelSignature = null;\n this._hiddenSeries = null;\n this._allSeriesInfo = null;\n this._allSeriesLabels = null;\n this._lastResults = null;\n }\n}\n\n// \u2500\u2500 Singleton window manager \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\nconst _openWindows = new Map();\n\n/**\n * Open or focus a plot popout window.\n *\n * @param {Object} options\n * @param {string} options.id - Unique window identifier\n * @param {string} options.title - Window title\n * @param {Object} options.plotConfig - PlotCell format: { layout, subplots }\n * @param {Function} options.getResults - Returns { time: number[], series: { [key]: number[] } }\n * @param {Object} options.services - { eventBus, logger }\n * @param {Object} [options.actuals] - ETL overlay data\n * @param {string|Function} [options.emptyMessage] - As PlotPopoutWindow's: a string\n * or `(subplot, results, index) => string`. Every option is forwarded.\n * @returns {PlotPopoutWindow}\n */\nexport async function openPlotPopoutWindow(options) {\n const { id } = options;\n let win = _openWindows.get(id);\n if (win?.isVisible) {\n win.bringToFront();\n return win;\n }\n\n // Forward the WHOLE options object. This used to destructure a fixed list of\n // eight names and rebuild the object from them, which means every option added\n // to the constructor from now on would be silently dropped on its way through\n // the factory \u2014 including `refreshEvent`, whose loss would show up as a plot\n // window that simply stops updating, with no error anywhere.\n win = new PlotPopoutWindow({\n ...options,\n onClose: () => _openWindows.delete(id),\n });\n _openWindows.set(id, win);\n\n await win.show();\n return win;\n}\n\n// \u2500\u2500 Raw-traces window (for dashboard tile expand) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n/**\n * Open a ManagedWindow with pre-built Plotly traces.\n *\n * Reuses the same toolbar, tab layout, and download logic as PlotPopoutWindow\n * but accepts ready-made `{ traces, layout }` instead of plotConfig + getResults.\n * Used by dashboard tile widgets whose getExpandData() returns raw Plotly specs.\n *\n * @param {Object} options\n * @param {string} options.id - Unique window identifier\n * @param {string} options.title - Window title\n * @param {Array} options.traces - Plotly trace objects\n * @param {Object} options.layout - Plotly layout object\n * @param {Array} [options.tableHeaders] - Column headers for Data tab\n * @param {Array} [options.tableRows] - Row data for Data tab\n * @param {Object} [options.services] - { eventBus, logger }\n * @param {Object} [options.host] - A Host (ui/js/host/host.js); backs Export PNG/CSV.\n * @returns {{ close: Function, bringToFront: Function }}\n */\nexport async function openRawTracesWindow({ id, title, traces, layout, frames, tableHeaders, tableRows, services, host }) {\n const existing = _openWindows.get(id);\n if (existing?.isVisible) {\n existing.bringToFront();\n return existing;\n }\n\n await ensurePlotly();\n\n // State\n let chartDiv = null;\n let chartCreated = false;\n let resizeObserver = null;\n let dataTable = null;\n let managedWindow = null;\n\n // \u2500\u2500 Build content DOM \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n const container = document.createElement('div');\n container.className = 'twm-plot-window-container';\n\n // Tab header\n const tabHeader = document.createElement('div');\n tabHeader.className = 'twm-code-tabs-header';\n\n const tabs = document.createElement('div');\n tabs.className = 'tabs twm-code-tabs';\n\n const plotTab = document.createElement('button');\n plotTab.className = 'twm-code-tab active';\n plotTab.type = 'button';\n plotTab.textContent = 'Plot';\n\n const dataTab = document.createElement('button');\n dataTab.className = 'twm-code-tab';\n dataTab.type = 'button';\n dataTab.textContent = 'Data';\n\n tabs.appendChild(plotTab);\n tabs.appendChild(dataTab);\n\n // Toolbar (same layout as PlotPopoutWindow)\n const toolbar = document.createElement('div');\n toolbar.className = 'twm-plot-window-toolbar';\n\n const spacer = document.createElement('div');\n spacer.style.flex = '1';\n toolbar.appendChild(spacer);\n\n const actionsGroup = document.createElement('div');\n actionsGroup.className = 'twm-plot-window-toolbar__group';\n\n const mkBtn = (icon, tooltip, onClick) => {\n const btn = document.createElement('button');\n btn.className = 'twm-btn-icon twm-has-tooltip';\n btn.type = 'button';\n btn.setAttribute('data-tooltip', tooltip);\n btn.innerHTML = `<span class=\"material-symbols-outlined\">${icon}</span>`;\n btn.addEventListener('click', (e) => { e.stopPropagation(); onClick(); });\n return btn;\n };\n\n actionsGroup.appendChild(mkBtn('image', 'Download plot as PNG', downloadPNG));\n actionsGroup.appendChild(mkBtn('download', 'Download data as CSV', downloadCSV));\n toolbar.appendChild(actionsGroup);\n\n tabHeader.appendChild(tabs);\n tabHeader.appendChild(toolbar);\n\n // Tab content\n const content = document.createElement('div');\n content.className = 'twm-plot-window-content';\n\n const plotContent = document.createElement('div');\n plotContent.className = 'twm-plot-tab-content active';\n plotContent.setAttribute('data-tab', 'plot');\n plotContent.style.cssText = 'display:flex; flex-direction:column;';\n\n chartDiv = document.createElement('div');\n chartDiv.className = 'twm-plot-window-chart';\n plotContent.appendChild(chartDiv);\n\n const dataContent = document.createElement('div');\n dataContent.className = 'twm-plot-tab-content';\n dataContent.setAttribute('data-tab', 'data');\n dataContent.style.cssText = 'display:none; flex-direction:column;';\n\n const dataTableContainer = document.createElement('div');\n dataTableContainer.style.cssText = 'flex:1; min-height:0; display:flex; flex-direction:column;';\n dataContent.appendChild(dataTableContainer);\n\n content.appendChild(plotContent);\n content.appendChild(dataContent);\n\n container.appendChild(tabHeader);\n container.appendChild(content);\n\n // Tab switching\n plotTab.addEventListener('click', () => {\n plotTab.classList.add('active');\n dataTab.classList.remove('active');\n toolbar.style.display = '';\n plotContent.style.display = 'flex';\n dataContent.style.display = 'none';\n if (chartCreated && window.Plotly && chartDiv) {\n try { window.Plotly.Plots.resize(chartDiv); } catch (_) {}\n }\n });\n\n dataTab.addEventListener('click', () => {\n dataTab.classList.add('active');\n plotTab.classList.remove('active');\n toolbar.style.display = 'none';\n plotContent.style.display = 'none';\n dataContent.style.display = 'flex';\n if (!dataTable && tableHeaders?.length) {\n dataTable = new DataTable(dataTableContainer, {\n headers: tableHeaders,\n rows: tableRows || [],\n pagination: true,\n pageSize: 100,\n selectable: true,\n copyable: true,\n sortable: true,\n filterable: true,\n readonly: true,\n emptyMessage: 'No data available',\n services,\n host,\n });\n dataTable.render();\n }\n });\n\n // \u2500\u2500 Create window \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n function dispose() {\n if (resizeObserver) { resizeObserver.disconnect(); resizeObserver = null; }\n if (dataTable) { dataTable.dispose(); dataTable = null; }\n if (chartDiv && window.Plotly) { try { purge(chartDiv); } catch (_) {} }\n chartDiv = null;\n chartCreated = false;\n managedWindow = null;\n _openWindows.delete(id);\n }\n\n managedWindow = new ManagedWindow({\n id: `raw-plot-${id}`,\n title: title || 'Chart',\n icon: 'monitoring',\n content: container,\n minWidth: 500,\n minHeight: 400,\n defaultWidth: 800,\n defaultHeight: 600,\n canMinimize: true,\n canMaximize: true,\n canResize: true,\n canDrag: true,\n onClose: dispose,\n });\n\n const handle = {\n get isVisible() { return managedWindow?.isVisible ?? false; },\n bringToFront() { managedWindow?.bringToFront?.(); },\n close() { managedWindow?.close?.(); },\n };\n\n _openWindows.set(id, handle);\n managedWindow.show();\n\n // Render plot\n const defaultMargin = { l: 60, r: 30, t: 40, b: 60 };\n const plotLayout = {\n paper_bgcolor: 'transparent',\n plot_bgcolor: 'transparent',\n font: { family: 'Inter, -apple-system, BlinkMacSystemFont, sans-serif', color: '#cccccc', size: 11 },\n hoverlabel: {\n bgcolor: '#1e2228',\n bordercolor: '#444444',\n font: { family: 'Inter, -apple-system, BlinkMacSystemFont, sans-serif', color: '#cccccc' },\n },\n autosize: true,\n hovermode: 'x unified',\n ...layout,\n margin: { ...defaultMargin, ...(layout?.margin || {}) },\n };\n\n await window.Plotly.newPlot(chartDiv, traces, plotLayout, {\n responsive: true,\n displayModeBar: true,\n displaylogo: false,\n modeBarButtonsToRemove: ['lasso2d', 'select2d', 'toImage'],\n });\n if (Array.isArray(frames) && frames.length) {\n try { await window.Plotly.addFrames(chartDiv, frames); }\n catch (err) { console.warn('[openRawTracesWindow] addFrames failed:', err); }\n }\n chartCreated = true;\n\n // Resize observer\n resizeObserver = createRafResizeObserver(() => {\n if (chartDiv && chartCreated && window.Plotly) {\n try { window.Plotly.Plots.resize(chartDiv); } catch (_) {}\n }\n });\n resizeObserver.observe(plotContent);\n\n // \u2500\u2500 Download helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n function notify(ntitle, message, severity = 'info') {\n services?.eventBus?.emit?.('toast:show', { title: ntitle, message, type: severity });\n }\n\n async function downloadPNG() {\n if (!chartDiv || !chartCreated || !window.Plotly) {\n notify('Download', 'Plot not ready', 'warn');\n return;\n }\n const filename = `${(title || 'chart').replace(/[^a-z0-9]/gi, '_')}.png`;\n try {\n const dataUrl = await window.Plotly.toImage(chartDiv, {\n format: 'png', width: 1920, height: 1080, scale: 2,\n });\n // null <=> no save dialog behind the capability (host.js) -> fall back.\n const dialogs = host?.dialogs;\n const result = dialogs\n ? await dialogs.saveFile({ data: dataUrl.split(',')[1], filename, kind: 'png' })\n : null;\n if (result) {\n if (result.ok) notify('Download', `Plot saved to ${result.path}`, 'success');\n else if (!result.cancelled) notify('Download', result.error || 'Failed to save image', 'error');\n } else {\n const link = document.createElement('a');\n link.href = dataUrl;\n link.download = filename;\n link.click();\n notify('Download', 'PNG download started', 'info');\n }\n } catch (err) {\n console.error('[openRawTracesWindow] PNG download failed:', err);\n notify('Download', 'Failed to generate PNG', 'error');\n }\n }\n\n async function downloadCSV() {\n if (!tableRows?.length) {\n notify('Download', 'No data available to download', 'warn');\n return;\n }\n const filename = `${(title || 'data').replace(/[^a-z0-9]/gi, '_')}_data.csv`;\n const csvEscape = (val) => {\n if (val == null) return '';\n const str = String(val);\n return (str.includes(',') || str.includes('\"') || str.includes('\\n'))\n ? `\"${str.replace(/\"/g, '\"\"')}\"` : str;\n };\n const lines = [(tableHeaders || []).join(',')];\n for (const row of tableRows) lines.push(row.map(csvEscape).join(','));\n const csv = lines.join('\\n');\n\n // null <=> no save dialog behind the capability (host.js) -> fall back.\n const dialogs = host?.dialogs;\n let result = null;\n if (dialogs) {\n try {\n result = await dialogs.saveFile({ data: csv, filename, kind: 'csv' });\n } catch (err) {\n console.error('[openRawTracesWindow] CSV download failed:', err);\n notify('Download', 'Failed to save file', 'error');\n return;\n }\n }\n if (result) {\n if (result.ok) notify('Download', `Saved ${tableRows.length} rows to ${result.path}`, 'success');\n else if (!result.cancelled) notify('Download', result.error || 'Failed to save file', 'error');\n } else {\n const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });\n const url = URL.createObjectURL(blob);\n const link = document.createElement('a');\n link.href = url;\n link.download = filename;\n link.click();\n URL.revokeObjectURL(url);\n notify('Download', 'Download started', 'info');\n }\n }\n\n return handle;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["Plotly", "current", "resize", "hasPlot", "Plotly", "results"]
|
|
7
7
|
}
|