import { extent, max } from 'd3-array' import { axisBottom, axisLeft } from 'd3-axis' import type { Axis } from 'd3-axis' import { schemeCategory10 } from 'd3-scale-chromatic' import { scaleLinear, scaleOrdinal, scaleTime } from 'd3-scale' import type { NumberValue, ScaleLinear, ScaleOrdinal, ScaleTime } from 'd3-scale' import { line as createLine } from 'd3-shape' import type { CurveFactory, Line } from 'd3-shape' import { timeParse } from 'd3-time-format' import { computed, toRaw, toValue } from 'vue' import type { ComputedRef, MaybeRefOrGetter } from 'vue' /** * One rendered line series: its source key, the SVG path `d` attribute and the * stroke color resolved from the ordinal color scale. */ export interface LineChartSeries { key: string path: string | null color: string | null } /** * A value formatter compatible with `useChart`'s `d3Formatter`: applies a d3 * format string or a custom function, returning the value untouched otherwise. */ export type LineChartFormatter = ( value: number | string, formatter?: ((v: number | string) => string) | string ) => string | number /** * The chart's inner padding box, once the axis margins are subtracted. */ export interface LineChartPadded { width: number height: number } /** * Reactive inputs driving {@link useLineChart}. They mirror the `LineChart` * component's loaded data, its measured padding box and the geometry-affecting * props, accepted as plain values, refs or getters so the composable adapts to * how the caller wires its state. */ export interface UseLineChartOptions { /** * The chart's loaded data (inline array or fetched), as exposed by `useChart`. */ loadedData: MaybeRefOrGetter[] | null> /** * The measured inner padding box (width/height in pixels) the scales map onto. */ padded: MaybeRefOrGetter /** * Field names for each series. When non-empty the chart is multi-line. */ keys: MaybeRefOrGetter /** * Field name holding the y value in single-series mode (when `keys` is empty). */ seriesName: MaybeRefOrGetter /** * Field name holding the x time/date value, parsed as a year (`%Y`). */ timeseriesKey: MaybeRefOrGetter /** * Explicit stroke colors for each line; falls back to `schemeCategory10`. */ lineColors: MaybeRefOrGetter /** * Optional d3 curve factory for line interpolation (defaults to linear). */ curve: MaybeRefOrGetter /** * The `d3Formatter` helper exposed by `useChart`, used to format y-axis ticks. */ d3Formatter: LineChartFormatter /** * Number of x-axis ticks or a d3 tick configuration. */ xAxisTicks: MaybeRefOrGetter any) | null> /** * Formatter function or d3 format string for y-axis tick labels. */ yAxisTickFormat: MaybeRefOrGetter<((v: any) => string) | string> /** * Number of y-axis ticks or a d3 tick configuration. */ yAxisTicks: MaybeRefOrGetter /** * Formats an x-axis year, as exposed by `useChart` (`xAxisYearFormat`). */ xAxisYearFormat: (year: number | string) => number | string } /** * Reactive API returned by {@link useLineChart}. */ export interface UseLineChart { isMultiLine: ComputedRef activeKeys: ComputedRef colorScale: ComputedRef> formattedData: ComputedRef[]> scaleX: ComputedRef> scaleY: ComputedRef> lines: ComputedRef line: ComputedRef xAxis: ComputedRef> yAxis: ComputedRef> } // Call the first argument if it's a function, or return it untouched. Mirrors // the d3 tick configuration, which accepts either a value or an accessor. function castCall(fnOrValue: any, ...rest: any[]) { return typeof fnOrValue === 'function' ? fnOrValue(...rest) : fnOrValue } // d3 parses a bare year ("%Y") into a Date positioned at the start of that year. const parseTime = timeParse('%Y') /** * Owns the pure d3 geometry of the `LineChart` component: it normalizes the data * (parsing the time field and casting series values), builds the time and linear * scales with their domains applied, derives every line path (single or * multi-series) and configures the x/y axes. It holds no DOM state — the measured * padding box is passed in, and the axis rendering stays in the component. * * @param options - Reactive geometry options (see {@link UseLineChartOptions}). * @returns The {@link UseLineChart} API of derived geometry and axis builders. * @remarks Internal building block of the `LineChart` component; not exported * from the package root. * @example * // Inside the `LineChart` component's `