import { getCommonOptions, mergeEchartWidgetConfig, type EchartOptionsProps, } from '../echart' import type { TimeseriesConfig, TimeseriesWidgetConfig, TimeseriesWidgetData, } from './types' import { flattenObjectArrayToCSV, buildLegendConfig, buildGridConfig, createTooltipFormatter, createChartDownloadConfig, applyYAxisFormatter, applyXAxisFormatter, buildSeriesLabelConfig, } from '../utils/chart-config' export const timeseriesDownloadConfig = createChartDownloadConfig(flattenObjectArrayToCSV) /** * Generates ECharts configuration for line and area chart widgets over time, with smooth curves, rotated axis labels, and CARTO qualitative color palette. * * @param props - Timeseries configuration including data and theme. * @returns Widget config with ECharts option object. */ export function timeseriesConfig( props: TimeseriesConfig, ): TimeseriesWidgetConfig { return { type: 'timeseries', option: mergeEchartWidgetConfig(getCommonOptions(props), getOption(props)), formatter: props.formatter, labelFormatter: props.labelFormatter, } } function getOption({ data = [], theme, formatter, labelFormatter, }: TimeseriesConfig): EchartOptionsProps { const hasLegend = (data?.length ?? 0) > 1 const yAxis = { type: 'value' as const, axisLabel: { margin: 0, padding: [ 0, parseInt(theme.spacing(0.75)), parseInt(theme.spacing(1.25)), -parseInt(theme.spacing(1)), ], show: true, showMaxLabel: true, showMinLabel: false, verticalAlign: 'bottom' as const, }, axisLine: { show: false, }, axisTick: { show: false, }, splitLine: { show: true, lineStyle: { color: theme.palette.black[4], }, }, } return { legend: buildLegendConfig({ hasLegend, labelFormatter }), grid: { ...buildGridConfig(hasLegend, theme), outerBounds: { left: parseInt(theme.spacing(3)), right: parseInt(theme.spacing(1)), top: parseInt(theme.spacing(2)), }, }, xAxis: applyXAxisFormatter( { type: 'category', axisTick: { alignWithLabel: true, }, axisLabel: { show: true, showMaxLabel: true, showMinLabel: true, rotate: 45, }, }, labelFormatter, ), yAxis: applyYAxisFormatter(yAxis, formatter), tooltip: { formatter: createTooltipFormatter((item) => { const value = item.value as Record const index = item.dimensionNames?.[item.encode?.y?.at(0) ?? 1] const _value = value[index ?? ''] const formattedValue = typeof _value === 'number' && formatter ? formatter(_value) : (_value ?? '') const marker = typeof item.marker === 'string' ? item.marker : '' const seriesName = item.seriesName ? `${item.seriesName}: ` : '' const name = labelFormatter ? String(labelFormatter(item.name ?? '')) : (item.name ?? '') return { name, seriesName, marker, value: formattedValue } }), }, color: Object.values(theme.palette.qualitative.bold), series: data.map((_: unknown, index: number) => ({ datasetIndex: index, type: 'line', smooth: true, emphasis: { focus: 'series', }, ...buildSeriesLabelConfig(formatter), })), } as EchartOptionsProps }