import type { ChartData } from './chart-data-transformer'; import type { ChartRenderOptions } from './chart-renderer'; import type { ChartToolbarItem } from '../types/grid.types'; import type { IconRenderer } from '../icons/icon-renderer'; export type ChartPanelType = 'column-grouped' | 'column-stacked' | 'column-100stacked' | 'bar-grouped' | 'bar-stacked' | 'bar-100stacked' | 'pie' | 'doughnut' | 'line' | 'area' | 'scatter' | 'polar' | 'funnel'; /** * The controller behind a {@link ChartPanel}. The panel is a passive view: it * measures itself, asks the host for render options, and forwards toolbar-menu * actions and drag events back to the host. All chart state lives in the host. */ export interface ChartPanelHost { /** Render options (from the chart model) sized to the panel's plot area. */ getRenderOptions(size: { width: number; height: number; }): ChartRenderOptions; /** Which `⋮` menu items to show, in order. Empty hides the menu. */ getToolbarItems(): ChartToolbarItem[]; /** Whether the chart is currently detached from the grid. */ isUnlinked(): boolean; /** "Edit Chart" — open the configuration tool panel. */ onEditChart(): void; /** "Advanced Settings" — open the tool panel on the Customize tab. */ onAdvancedSettings(): void; /** * Toggle the grid link: unlink freezes the chart as a snapshot, re-link * resumes live updates and immediately refreshes from the grid. */ onToggleLink(): void; /** Fired as the panel card moves (drag / fullscreen / recenter) so the tool panel can re-dock. */ onMove(rect: DOMRect): void; /** Fired when the panel closes so the host can dispose its chart. */ onClose(): void; } export declare class ChartPanel { private containerEl; private iconRenderer?; private backdropEl; private cardEl; private bodyEl; private chartAreaEl; private canvasEl; private dotsMenuEl; private dotsBtnEl; /** * Document-level `mousedown` listener that dismisses the download menu when * the user clicks outside it. Held so it can be detached on close, avoiding a * leaked listener across panel lifecycles. */ private outsideMousedownHandler; private fullscreenBtnEl; private legendEl; private renderer; private resizeObserver; private isFullscreen; private currentData; private currentType; private currentTitle; /** Dataset indices the user has toggled off via the legend (cartesian charts). */ private hiddenSeries; /** Category/slice indices toggled off via the legend (categorical charts). */ private hiddenSlices; /** Current top-left position of the card within the backdrop. */ private panelX; private panelY; /** Controller that supplies render options and handles menu/drag events. */ private host; /** Guards {@link close} against re-entrancy when the host disposes us. */ private closing; /** * @param containerEl - Host element the panel mounts into. * @param iconRenderer - Resolves chart chrome icons through the shared * registry, so they follow the active theme's icon pack like the rest of the * grid. Optional only so the panel stays constructible in isolation; when * absent, chrome renders without glyphs rather than with off-theme ones. */ constructor(containerEl: HTMLElement, iconRenderer?: IconRenderer | undefined); /** Resolves a chrome icon, or `''` when no renderer was supplied. */ private icon; /** Attaches the controlling host. Must be set before {@link open}. */ setHost(host: ChartPanelHost): void; /** * Replaces the chart data and re-renders. Called by the host when the model * changes or the linked grid data refreshes. Rebuilds the interactive legend. */ update(data: ChartData | null): void; /** The chart card element, for external docking (e.g. the config tool panel). */ getCardElement(): HTMLElement | null; /** * The scrollable body element that hosts the canvas. The configuration drawer * mounts here so it slides in over the plot area while the header (close / * fullscreen) and legend stay accessible. */ getBodyElement(): HTMLElement | null; /** * Reserves `px` of space on the right of the plot for the configuration drawer, * so the chart reflows beside it instead of being hidden underneath. Passing 0 * releases the reservation. The chart re-renders to fill the new area (the * chart-area ResizeObserver also fires as the reflow transition runs). */ setConfigReserve(px: number): void; /** Updates the chart type used for subsequent renders. */ setChartType(type: ChartPanelType): void; /** Returns a data-URL snapshot of the current chart, or null if not rendered. */ getImageDataURL(format?: 'png' | 'jpeg'): string | null; /** Triggers a browser download of the chart. */ download(format?: 'png' | 'jpeg'): void; open(type: ChartPanelType, title: string, data: ChartData | null): void; close(): void; private buildDom; /** * Builds the `⋮` toolbar button and its dropdown menu. Items come from the * host (Edit Chart / Advanced Settings / Unlink / Download); Download is always * handled internally. Skipped entirely when the host returns no items. */ private buildDotsMenu; /** Expands the requested toolbar items into concrete menu entries (labels + actions). */ private resolveMenuEntries; /** * Position the card at the center of the backdrop. * Called once after building the DOM and on fullscreen exit. */ private centerPanel; private applyPosition; /** * Wire drag-to-move onto the header bar. * Clamped strictly within the backdrop bounds so the panel never escapes the grid. */ private attachDrag; private closeDotsMenu; /** * Registers a document-level `mousedown` listener that dismisses the download * menu on an outside click. * * Clicks that land on the menu or its trigger button are deliberately ignored: * `mousedown` fires before `click`, so closing the menu here (which sets it to * `display: none`) would remove the menu item from the layout before its own * `click` handler could run — silently swallowing the download. Guarding on the * target keeps the menu alive long enough for the item's `click` to fire, then * that handler closes the menu itself. */ private attachOutsideMousedown; /** Removes the outside-click listener registered by {@link attachOutsideMousedown}. */ private detachOutsideMousedown; private toggleFullscreen; private renderChart; /** * Builds the render options for the current size. Prefers the host's model-derived * options, then forces `showLegend: false` because the panel draws its own * interactive HTML legend below the canvas. Falls back to a minimal default when * no host is attached. */ private resolveRenderOptions; /** * Whether the HTML legend below the canvas should be shown for `data`: * multi-series cartesian charts (one item per series) OR any categorical * chart with at least one category (one item per slice/row/spoke). */ private shouldShowLegend; /** Whether the current chart type draws one colored mark per category. */ private isCategorical; /** The resolved theme series palette, used to color per-slice legend swatches. */ private palette; /** * Per-series color overrides from the chart model, keyed by series label. * * Read straight off the host's render options — the same object the renderer * is given — so the legend can never disagree with the canvas about an * explicitly configured series color. The size passed in is irrelevant here: * `seriesColors` is layout-independent, and this runs on legend rebuilds only, * never per frame. */ private seriesColorOverrides; /** * Populates the HTML legend bar. For categorical charts each item is a * category (slice); for cartesian charts each item is a series. Clicking an * item toggles that slice/series in or out with an animation and dims the * entry. * * Swatch colors are resolved through {@link resolveSeriesColors} — the very * chain `ChartRenderer` applies — because the renderer colors a private copy * of the data and leaves `dataset.color` undefined on the panel's own * `ChartData`. Reading that field directly is what previously painted every * swatch in the same fallback blue while the bars were correctly varied. */ private buildLegend; /** * Toggles a legend entry. For categorical charts this hides/shows a single * slice (its value is zeroed so sibling colors stay stable); for cartesian * charts it animates a whole series in/out. */ private handleLegendToggle; /** * Returns a shallow copy of `data` with hidden categorical slices zeroed, so * they collapse to nothing while every remaining slice keeps its palette color * (which is assigned by original index). */ private applyHiddenSlices; private downloadChart; } //# sourceMappingURL=chart-panel.d.ts.map