import React from 'react' import { Bar, BarChart, CartesianGrid, Line, LineChart, Tooltip, XAxis, YAxis, PieChart, Pie, Cell, ScatterChart, Scatter, AreaChart, Area, ComposedChart, } from 'recharts' import { ChartType, RenderChartProps, TickProps, AxisType, AxisIntervalType, SankeyData, DotItemDotProps, FlattenedDataPoint, } from './types' import SankeyChartWrapper from './SankeyChartWrapper' import FunnelChart from './FunnelChart' import { formatNumber, getAxisFormatter, lightenHexColor, transformScatterData, generateConsistentDateTimeTicks, } from './ChartUtils' import { parseTimestamp } from './DateTimeFormatter' import { CustomTooltip } from './CustomTooltip' import { FOUNDATION_THEME } from '../../tokens' import Text from '../Text/Text' import Block from '../Primitives/Block/Block' import { Button, ButtonType } from '../Button' import { DEFAULT_COLORS } from './utils' export const renderChart = ({ chartName, flattenedData, chartType, hoveredKey, lineKeys, colors, setHoveredKey, data: originalData, selectedKeys, isSmallScreen = false, barsize, xAxis, yAxis, tooltip, funnelConfig, noData, height, CustomizedDot, lineSeriesKeys, onKeyClick, chartTokens, }: RenderChartProps) => { const finalXAxis = { label: xAxis?.label, showLabel: xAxis?.showLabel ?? false, interval: xAxis?.interval, show: xAxis?.show ?? true, ...xAxis, } const finalYAxis = { label: yAxis?.label, showLabel: yAxis?.showLabel ?? false, interval: yAxis?.interval, show: yAxis?.show ?? true, ...yAxis, } const isDateTimeAxis = finalXAxis.type === AxisType.DATE_TIME // Auto-generate consistent ticks for DATE_TIME axes (like Highcharts) if ( isDateTimeAxis && finalXAxis.autoConsistentTicks !== false && !finalXAxis.ticks && originalData.length > 0 ) { // Only apply maxTicks if explicitly set, otherwise let the formatter decide const { ticks } = generateConsistentDateTimeTicks(originalData, { maxTicks: finalXAxis.maxTicks ? isSmallScreen ? Math.max(3, Math.floor(finalXAxis.maxTicks / 2)) : finalXAxis.maxTicks : undefined, // Don't limit ticks when maxTicks is not explicitly set dateOnly: finalXAxis.dateOnly, timeOnly: finalXAxis.timeOnly, showYear: finalXAxis.showYear, useUTC: finalXAxis.useUTC, formatString: finalXAxis.formatString, }) finalXAxis.ticks = isDateTimeAxis ? ticks.map((tick) => parseTimestamp(tick) ?? Number(tick)) : ticks // Enable smart date/time format by default (alternates between date and time) // Only if user hasn't specified dateOnly, timeOnly, or formatString if ( finalXAxis.smartDateTimeFormat === undefined && !finalXAxis.dateOnly && !finalXAxis.timeOnly && !finalXAxis.formatString ) { finalXAxis.smartDateTimeFormat = true } } // When using custom ticks, set interval to 0 to show all ticks. // On small screens use preserveStartEnd so recharts auto-hides if (finalXAxis.ticks && finalXAxis.interval === undefined) { finalXAxis.interval = isSmallScreen ? AxisIntervalType.PRESERVE_START_END : 0 } const getColor = (key: string, chartType: ChartType) => { // Try to find color by matching key first const colorByKey = colors.find((color) => color.key === key) // If not found by key, use backup color from DEFAULT_COLORS const originalIndex = lineKeys.indexOf(key) const backupColor = DEFAULT_COLORS[originalIndex % DEFAULT_COLORS.length] const baseColor = colorByKey || backupColor const colorValue = baseColor.color if (chartType === ChartType.BAR) { return hoveredKey === null ? colorValue : hoveredKey === key ? colorValue : lightenHexColor(colorValue, 0.3) } if (hoveredKey && hoveredKey !== key) { return lightenHexColor(colorValue, 0.3) } return colorValue } const chartConfig = { tickFill: chartTokens?.axis.labelColor ?? FOUNDATION_THEME.colors.gray[400], tickFontSize: 14, tickFontWeight: FOUNDATION_THEME.font.weight[500], axisLine: false, tickLine: false, labelFill: chartTokens?.axis.labelColor ?? FOUNDATION_THEME.colors.gray[400], labelFontSize: 14, labelFontWeight: FOUNDATION_THEME.font.weight[500], gridStroke: chartTokens?.axis.gridLineColor ?? FOUNDATION_THEME.colors.gray[150], } const processedData = isDateTimeAxis ? flattenedData.map((item) => { const numericTimestamp = typeof item.name === 'number' ? item.name : parseTimestamp(item.name) return { ...item, __blendTimestamp: numericTimestamp ?? (typeof item.name === 'string' ? Number(item.name) : item.name), } }) : flattenedData const xAxisDataKey = isDateTimeAxis ? '__blendTimestamp' : 'name' if (processedData.length === 0) { return ( {noData?.slot && noData?.slot} {noData?.title || 'No data available'} {noData?.subtitle || 'Data will appear here once available'} {noData?.button && (