import { LayoutRect, ThemeContext } from '../../shared/kernel'; import { FontOptions, PaddingValue, Pixels, Switchable } from '../../shared/options'; import { Group } from '../../shared/scene'; export interface CaptionOptions extends Switchable, FontOptions { text?: string; /** Horizontal alignment within the chart width ('center' by default). */ textAlign?: 'left' | 'center' | 'right'; /** Vertical placement: above ('top', default) or below ('bottom') the plot. */ position?: 'top' | 'bottom'; /** * Padding around the caption text in any CSS-like shorthand — `8`, `[8, 12]`, * `[8, 12, 4, 0]` or `{ top, right, bottom, left }`. By default only the * plot-facing side is padded (8 px): below the caption in the 'top' zone, * above it in the 'bottom' zone. When both captions share a zone, the padding * of the outer one separates the two captions, and the padding of the one * closest to the plot separates it from the plot. Horizontal padding narrows * the width the text is wrapped within. */ padding?: PaddingValue; /** * Gap on the plot-facing side of the caption (8 by default). * * @deprecated Use `padding` — it covers the same gap and the other three * sides. Kept as the default for the plot-facing side of `padding`. */ spacing?: Pixels; /** * Break the text onto several lines when it does not fit the available width * (true by default). Line breaks written as '\n' always apply. */ wrap?: boolean; } export interface CaptionLayoutContext { measureText: (text: string, font: string) => number; /** * Box the captions flow around — a floating legend, in scene coordinates. * Lines overlapping it vertically are laid out in the wider side gap. Asked * again with a width cap when a line has nowhere to go beside the box: the * legend gives up width rather than have the caption land on it. Undefined * (or a callback returning it) — there is nothing to flow around. */ obstacle?: (widthCap?: number) => LayoutRect | undefined; } interface CaptionLine { text: string; /** Anchor point of the line, matching `align`. */ x: number; y: number; align: 'left' | 'center' | 'right'; } interface CaptionPlacement { role: 'title' | 'subtitle'; options: CaptionOptions; fontSize: number; /** Height of the whole block: the lines plus the vertical padding. */ height: number; lines: CaptionLine[]; /** Width the widest line is missing in the gap the obstacle left it (0 — everything fits). */ shortfall: number; } /** Whether anything will be drawn at all — lets callers skip preparing the layout context. */ export declare function hasCaptions(title: CaptionOptions | undefined, subtitle: CaptionOptions | undefined): boolean; /** * Places the title and subtitle around the plot: 'top' captions stack below * `padding.top`, 'bottom' ones sit above `padding.bottom` (the title stays * above the subtitle in both zones, the caption padding faces the plot). Long * text wraps within the available width, flowing around `context.obstacle`. * Returns the placements plus the space consumed from each edge, chart padding * excluded. * * When a line has nowhere to go beside the obstacle, the obstacle is asked to * fit into a narrower width and the whole layout is taken again — a floating * legend gives up the room the caption is missing instead of being written * over. It gives up no more than half the width: past that its own labels * would be the ones with nowhere to go. */ export declare function layoutCaptions(title: CaptionOptions | undefined, subtitle: CaptionOptions | undefined, theme: ThemeContext, width: number, height: number, padding: { top: number; right: number; bottom: number; left: number; }, context: CaptionLayoutContext): { placements: CaptionPlacement[]; top: number; bottom: number; }; /** * Renders the title and subtitle around the plot (see {@link layoutCaptions}) * and returns the space consumed from each edge, padding excluded. */ export declare function renderCaptions(layer: Group, title: CaptionOptions | undefined, subtitle: CaptionOptions | undefined, theme: ThemeContext, width: number, height: number, padding: { top: number; right: number; bottom: number; left: number; }, context: CaptionLayoutContext): { top: number; bottom: number; }; export {};