import { max, range, sum } from 'd3-array' import { axisBottom, axisLeft } from 'd3-axis' import type { Axis } from 'd3-axis' import { scaleBand, scaleLinear } from 'd3-scale' import type { NumberValue, ScaleBand, ScaleLinear } from 'd3-scale' import iteratee from 'lodash/iteratee' import sortByFn from 'lodash/sortBy' import { computed, toValue } from 'vue' import type { ComputedRef, MaybeRefOrGetter } from 'vue' /** * The geometry of a single rendered column, in canvas pixels, carrying its * source datum and (for waterfall charts) a flag marking the total column. */ export interface ColumnChartBar { datum: Record width: number height: number x: number y: number isTotal?: boolean } /** * The chart's margins, in canvas pixels. */ export interface ColumnChartMargin { left: number right: number top: number bottom: number } /** * The chart's inner padding box, once the axis margins are subtracted. */ export interface ColumnChartPadded { width: number height: number } /** * A value formatter compatible with `useChart`'s `d3Formatter`: applies a d3 * format string or a custom function, returning the value untouched otherwise. */ export type ColumnChartFormatter = ( value: number | string, formatter?: ((v: number | string) => string) | string ) => string | number /** * Reactive inputs driving {@link useColumnChart}. They mirror the `ColumnChart` * component's loaded data, its measured dimensions 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 UseColumnChartOptions { /** * The chart's loaded data (inline array or fetched), as exposed by `useChart`. */ loadedData: MaybeRefOrGetter[] | null> /** * Measured outer width of the chart, in pixels. */ width: MaybeRefOrGetter /** * Measured outer height of the chart, in pixels. */ height: MaybeRefOrGetter /** * Measured (or fixed) width reserved for the y-axis labels, in pixels. */ labelWidth: MaybeRefOrGetter /** * Measured height of the y-axis labels, in pixels. */ labelHeight: MaybeRefOrGetter /** * Measured height of the x-axis tick labels, in pixels. */ bucketHeight: MaybeRefOrGetter /** * Measured width of the x-axis tick labels, in pixels. */ bucketWidth: MaybeRefOrGetter /** * The `d3Formatter` helper exposed by `useChart`, used to format axis ticks. */ d3Formatter: ColumnChartFormatter sortBy: MaybeRefOrGetter seriesName: MaybeRefOrGetter timeseriesKey: MaybeRefOrGetter maxValue: MaybeRefOrGetter barPadding: MaybeRefOrGetter barMargin: MaybeRefOrGetter noXAxis: MaybeRefOrGetter noYAxis: MaybeRefOrGetter xAxisTickCollapse: MaybeRefOrGetter xAxisTickFormat: MaybeRefOrGetter<((v: any) => string) | string> xAxisTicks: MaybeRefOrGetter yAxisTickFormat: MaybeRefOrGetter<((v: any) => string) | string> yAxisTicks: MaybeRefOrGetter waterfall: MaybeRefOrGetter waterfallTotal: MaybeRefOrGetter waterfallTotalLabel: MaybeRefOrGetter } /** * Reactive API returned by {@link useColumnChart}. */ export interface UseColumnChart { sortedData: ComputedRef[]> margin: ComputedRef padded: ComputedRef scaleX: ComputedRef> scaleY: ComputedRef> waterfallTotalValue: ComputedRef bars: ComputedRef xAxisHiddenTicks: ComputedRef /** * Ticks to actually render on the x-axis: the collapsed, surviving subset * of `sortedData`'s keys, not one entry per datum. Do not zip this with * {@link bars} by index to derive your own labels — their lengths diverge * as soon as `xAxisTickCollapse` yields a stride above 1; match by value * against each bar's `datum` instead. */ xAxisTickValues: ComputedRef xAxis: ComputedRef> yAxis: ComputedRef> } /** * Owns the pure d3 geometry of the `ColumnChart` component: it sorts the data, * builds the band and linear scales, derives every column (including the * waterfall layout and its optional total), and configures the x/y axes. It * holds no DOM state — the measured dimensions are passed in, and the axis * rendering and tooltips stay in the component. * * @param options - Reactive geometry options (see {@link UseColumnChartOptions}). * @returns The {@link UseColumnChart} API of derived geometry and axis builders. * @example * // Internal building block of the `ColumnChart` component; not exported from * // the package root. Inside a `