@extend-ai/react-xlsx 0.18.1 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +154 -6
- package/dist/chart-renderer-3K2VKB5I.js +5042 -0
- package/dist/chart-renderer-3K2VKB5I.js.map +1 -0
- package/dist/{chart-renderer-ZUWRNNZT.cjs → chart-renderer-HVOEAQXK.cjs} +5 -5
- package/dist/{chart-renderer-ZUWRNNZT.cjs.map → chart-renderer-HVOEAQXK.cjs.map} +1 -1
- package/dist/chart-renderer-LHXMRBGR.cjs +5043 -0
- package/dist/chart-renderer-LHXMRBGR.cjs.map +1 -0
- package/dist/{chart-renderer-HQSQHDCB.js → chart-renderer-R2B4I2HL.js} +2 -2
- package/dist/chunk-3O2QY6LA.js +50 -0
- package/dist/{chunk-OZLJPZUX.js.map → chunk-3O2QY6LA.js.map} +1 -1
- package/dist/chunk-4VX5HTCF.cjs +50 -0
- package/dist/chunk-4VX5HTCF.cjs.map +1 -0
- package/dist/chunk-CJBI5F6V.cjs +816 -0
- package/dist/chunk-CJBI5F6V.cjs.map +1 -0
- package/dist/chunk-NBH72POD.js +816 -0
- package/dist/chunk-NBH72POD.js.map +1 -0
- package/dist/{chunk-OZLJPZUX.js → chunk-O7S3Y6II.js} +10 -6
- package/dist/chunk-O7S3Y6II.js.map +1 -0
- package/dist/{chunk-FO6MIHX4.cjs → chunk-T5WZHPIN.cjs} +2 -2
- package/dist/{chunk-FO6MIHX4.cjs.map → chunk-T5WZHPIN.cjs.map} +1 -1
- package/dist/chunk-TYJLNPNE.cjs +26972 -0
- package/dist/chunk-TYJLNPNE.cjs.map +1 -0
- package/dist/chunk-Y737JKUG.js +26969 -0
- package/dist/chunk-Y737JKUG.js.map +1 -0
- package/dist/{chunk-WFQGZI2Z.cjs → chunk-ZIO47YMT.cjs} +12 -8
- package/dist/chunk-ZIO47YMT.cjs.map +1 -0
- package/dist/index.cjs +588 -11267
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -14
- package/dist/index.d.ts +3 -14
- package/dist/index.js +474 -11153
- package/dist/index.js.map +1 -1
- package/dist/internal-DSz8QMhK.d.cts +1496 -0
- package/dist/internal-DSz8QMhK.d.ts +1496 -0
- package/dist/internal.cjs +24 -0
- package/dist/internal.cjs.map +1 -0
- package/dist/internal.d.cts +3 -0
- package/dist/internal.d.ts +3 -0
- package/dist/internal.js +23 -0
- package/dist/internal.js.map +1 -0
- package/dist/{region-map-geography-5E5SVPGS.cjs → region-map-geography-6TGXBY3V.cjs} +2 -2
- package/dist/{region-map-geography-5E5SVPGS.cjs.map → region-map-geography-6TGXBY3V.cjs.map} +1 -1
- package/dist/{spreadsheet-font-assets-7QMV43XD.cjs → spreadsheet-font-assets-4AHYDTAQ.cjs} +2 -2
- package/dist/{spreadsheet-font-assets-7QMV43XD.cjs.map → spreadsheet-font-assets-4AHYDTAQ.cjs.map} +1 -1
- package/dist/surface-regl-KW4JL325.js +723 -0
- package/dist/surface-regl-KW4JL325.js.map +1 -0
- package/dist/surface-regl-MAPCPD7W.cjs +724 -0
- package/dist/surface-regl-MAPCPD7W.cjs.map +1 -0
- package/dist/{surface-regl-WVLW3SEA.cjs → surface-regl-PWTZWQQS.cjs} +2 -2
- package/dist/{surface-regl-WVLW3SEA.cjs.map → surface-regl-PWTZWQQS.cjs.map} +1 -1
- package/dist/vanilla.cjs +20 -0
- package/dist/vanilla.cjs.map +1 -0
- package/dist/vanilla.d.cts +9 -0
- package/dist/vanilla.d.ts +9 -0
- package/dist/vanilla.js +19 -0
- package/dist/vanilla.js.map +1 -0
- package/dist/xlsx-worker.js +2888 -34
- package/dist/xlsx-worker.js.map +1 -1
- package/package.json +23 -3
- package/dist/chunk-WFQGZI2Z.cjs.map +0 -1
- /package/dist/{chart-renderer-HQSQHDCB.js.map → chart-renderer-R2B4I2HL.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/react-xlsx/react-xlsx/packages/react-xlsx/dist/chart-renderer-LHXMRBGR.cjs","../src/chart-renderer.tsx"],"names":[],"mappings":"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CA,IAAA;AACF,EAAA;AACF;AAEA;AACE,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACF;AAEA;AACE,EAAA;AACA,EAAA;AACA,EAAA;AACF;AAEA;AACE,EAAA;AACE,IAAA;AACF,EAAA;AACA,EAAA;AACE,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACA,EAAA;AACA,EAAA;AACF;AAEA;AACE,EAAA;AAMF;AAEA;AACE,EAAA;AACA,EAAA;AACA,EAAA;AAGA,EAAA;AACF;AAEA;AACE,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACF;AAEA;AACE,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACE,IAAA;AACF,EAAA;AACA,EAAA;AACF;AAEA;AACE,EAAA;AAKA,EAAA;AACE,IAAA;AACF,EAAA;AACA,EAAA;AAGA,EAAA;AAGA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AAGA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACE,IAAA;AACF,EAAA;AACA,EAAA;AACA,EAAA;AACE,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACF;AAEA;AACE,EAAA;AACF;AAEA;AACE,EAAA;AACA,EAAA;AACE,IAAA;AACA,IAAA;AACE,MAAA;AACF,IAAA;AACF,EAAA;AACA,EAAA;AACF;AAEA;AACE,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACF;AAEA;AACE,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AAIF;AAEA;AACE,EAAA;AACE,IAAA;AACF,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACE,IAAA;AACF,EAAA;AACE,IAAA;AACF,EAAA;AACA,EAAA;AACE,IAAA;AACA,IAAA;AACA,IAAA;AA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","file":"/home/runner/work/react-xlsx/react-xlsx/packages/react-xlsx/dist/chart-renderer-LHXMRBGR.cjs","sourcesContent":[null,"import { getBuiltinChartColor, getBuiltinChartSurfaceLine, resolveBuiltinChartColor } from \"./builtin-chart-styles\";\nimport { hierarchy as d3Hierarchy, partition as d3Partition, treemap as d3Treemap, treemapBinary, treemapDice, treemapSquarify } from \"d3-hierarchy\";\nimport * as React from \"react\";\nimport { shadeSurfaceMatteColor, surfaceNormal, transformSurfaceNormal } from \"./surface-lighting\";\nimport { clipSurfaceBand, normalizeSurfaceValue, surfaceDataRatios, surfaceBandEdges, triangulateSurfaceQuad } from \"./surface-geometry\";\nimport { scaleBand, scaleLinear, scalePoint } from \"d3-scale\";\nimport {\n arc as d3Arc,\n area as d3Area,\n curveCatmullRom,\n curveLinear,\n curveLinearClosed,\n line as d3Line,\n pie as d3Pie\n} from \"d3-shape\";\nimport type { CurveFactory } from \"d3-shape\";\nimport { regionMapResources, surfaceRenderer } from \"./chart-loader\";\nimport { useChartModule } from \"./use-chart-module\";\nimport type { RegionMapResources, RegionMapFeature } from \"./region-map-geography\";\nimport type { HierarchyNode, HierarchyRectangularNode } from \"d3-hierarchy\";\nimport type { FeatureCollection, Geometry } from \"geojson\";\nimport type { XlsxChart, XlsxChartAxis, XlsxChartElementSelection, XlsxChartSeries, XlsxChartTypeGroup, XlsxImageRect } from \"./types\";\n\ntype ChartRendererPalette = {\n border: string;\n mutedText: string;\n surface: string;\n text: string;\n};\n\nexport type ChartSvgProps = {\n chart: XlsxChart;\n onChartElementDoubleClick?: (selection: XlsxChartElementSelection, event: React.MouseEvent<SVGSVGElement>) => void;\n onChartElementPointerDown?: (selection: XlsxChartElementSelection, event: React.PointerEvent<SVGSVGElement>) => void;\n palette: ChartRendererPalette;\n rect: XlsxImageRect;\n selectedChartElement?: XlsxChartElementSelection | null;\n};\n\ntype RegionMapPlotProps = Pick<ChartSvgProps, \"chart\" | \"palette\" | \"selectedChartElement\"> & { layout: ChartLayout };\n\nfunction RegionMapPlot({ chart, palette, layout, selectedChartElement }: RegionMapPlotProps) {\n const resources = useChartModule(regionMapResources);\n return resources\n ? renderRegionMapChart(chart, palette, layout, selectedChartElement, resources)\n : null;\n}\n\nfunction SurfaceChartComposite({\n loadingFallback,\n ...props\n}: React.ComponentProps<typeof import(\"./surface-regl\").MemoSurfaceChartComposite> & { loadingFallback: React.ReactNode }) {\n const renderer = useChartModule(surfaceRenderer);\n return renderer ? <renderer.MemoSurfaceChartComposite {...props} /> : <>{loadingFallback}</>;\n}\n\ntype LegendItem = {\n color: string;\n label: string;\n};\n\ntype PlotRect = {\n height: number;\n left: number;\n top: number;\n width: number;\n};\n\ntype ChartLayout = {\n height: number;\n legendBounds?: PlotRect;\n legendItems: LegendItem[];\n legendPosition: string | undefined;\n plot: PlotRect;\n titleHeight: number;\n width: number;\n};\n\ntype BarRect = {\n capEnd?: boolean;\n capStart?: boolean;\n categoryIndex: number;\n bottomScale?: number;\n color: string;\n depthOrder?: number;\n depthOffsetX?: number;\n depthOffsetY?: number;\n depthX?: number;\n depthY?: number;\n gradientId?: string;\n height: number;\n invertedNegative?: boolean;\n isHorizontal: boolean;\n key: string;\n left: number;\n shape3d?: string;\n seriesIndex: number;\n stroke: string;\n strokeWidth: number;\n topScale?: number;\n value: number;\n width: number;\n top: number;\n};\n\ntype ChartElementDataOptions = {\n selectionMode?: \"seriesFirst\";\n};\n\nfunction chartElementDataProps(seriesIndex: number, pointIndex?: number, options?: ChartElementDataOptions) {\n return {\n \"data-xlsx-chart-point-index\": typeof pointIndex === \"number\" ? String(pointIndex) : undefined,\n \"data-xlsx-chart-selection-mode\": options?.selectionMode,\n \"data-xlsx-chart-series-index\": String(seriesIndex),\n style: {\n cursor: \"pointer\",\n pointerEvents: \"all\"\n } as React.CSSProperties\n };\n}\n\nfunction barChartElementDataProps(seriesIndex: number, pointIndex: number) {\n return chartElementDataProps(seriesIndex, pointIndex, { selectionMode: \"seriesFirst\" });\n}\n\nfunction resolveChartElementTarget(target: EventTarget | null) {\n if (!(target instanceof Element)) {\n return null;\n }\n\n return target.closest(\"[data-xlsx-chart-series-index]\") as HTMLElement | SVGElement | null;\n}\n\nfunction resolveChartSelectionFromTarget(\n chart: XlsxChart,\n target: EventTarget | null,\n selectedChartElement: XlsxChartElementSelection | null | undefined\n): XlsxChartElementSelection | null {\n const element = resolveChartElementTarget(target);\n if (!element) {\n return selectedChartElement?.chartId === chart.id\n ? { chartId: chart.id, kind: \"chart\" }\n : { chartId: chart.id, kind: \"chart\" };\n }\n\n const seriesIndex = Number(element.dataset.xlsxChartSeriesIndex);\n if (!Number.isInteger(seriesIndex) || seriesIndex < 0 || seriesIndex >= chart.series.length) {\n return null;\n }\n\n const series = chart.series[seriesIndex];\n if (!series) {\n return null;\n }\n\n const rawPointIndex = element.dataset.xlsxChartPointIndex;\n const rawElementKind = element.dataset.xlsxChartElementKind;\n const selectionMode = element.dataset.xlsxChartSelectionMode;\n const pointIndex = rawPointIndex == null || rawPointIndex === \"\" ? null : Number(rawPointIndex);\n const hasPoint = pointIndex != null && Number.isInteger(pointIndex) && pointIndex >= 0;\n const sameSelectedSeries = selectedChartElement?.chartId === chart.id\n && selectedChartElement.kind !== \"chart\"\n && selectedChartElement.seriesIndex === seriesIndex;\n if (hasPoint && (selectionMode !== \"seriesFirst\" || sameSelectedSeries)) {\n return {\n chartId: chart.id,\n kind: \"point\",\n pointIndex,\n seriesId: series.id,\n seriesIndex\n };\n }\n\n return {\n chartId: chart.id,\n kind: rawElementKind === \"legendEntry\" ? \"legendEntry\" : \"series\",\n seriesId: series.id,\n seriesIndex\n };\n}\n\nfunction isSelectedChartSeries(\n selectedChartElement: XlsxChartElementSelection | null | undefined,\n chartId: string,\n seriesIndex: number\n) {\n return selectedChartElement?.chartId === chartId\n && selectedChartElement.kind !== \"chart\"\n && selectedChartElement.seriesIndex === seriesIndex;\n}\n\nfunction isSelectedChartPoint(\n selectedChartElement: XlsxChartElementSelection | null | undefined,\n chartId: string,\n seriesIndex: number,\n pointIndex: number\n) {\n return selectedChartElement?.chartId === chartId\n && selectedChartElement.kind === \"point\"\n && selectedChartElement.seriesIndex === seriesIndex\n && selectedChartElement.pointIndex === pointIndex;\n}\n\nfunction isSelectedChartPointOrSeries(\n selectedChartElement: XlsxChartElementSelection | null | undefined,\n chartId: string,\n seriesIndex: number,\n pointIndex: number\n) {\n return isSelectedChartPoint(selectedChartElement, chartId, seriesIndex, pointIndex)\n || (\n isSelectedChartSeries(selectedChartElement, chartId, seriesIndex)\n && selectedChartElement?.kind !== \"point\"\n );\n}\n\nfunction renderSelectionRectHandles(\n key: string,\n left: number,\n top: number,\n width: number,\n height: number,\n color = \"#64748b\"\n) {\n return renderSelectionPointHandles(\n key,\n [\n { x: left, y: top },\n { x: left + width, y: top },\n { x: left, y: top + height },\n { x: left + width, y: top + height }\n ],\n color\n );\n}\n\nfunction renderSelectionPointHandles(\n key: string,\n points: Array<{ x: number; y: number }>,\n color = \"#64748b\"\n) {\n const radius = 3;\n\n return (\n <g key={key} pointerEvents=\"none\">\n {points.map((point, index) => (\n <circle\n cx={point.x}\n cy={point.y}\n fill=\"#ffffff\"\n key={`${key}-handle-${index}`}\n r={radius}\n stroke={color}\n strokeWidth={1.1}\n style={{ filter: \"drop-shadow(0 1px 2px rgba(15, 23, 42, 0.18))\" }}\n vectorEffect=\"non-scaling-stroke\"\n />\n ))}\n </g>\n );\n}\n\ntype ChartHierarchyDatum = {\n children?: ChartHierarchyDatum[];\n colorIndex?: number;\n name: string;\n value?: number;\n};\n\ntype ComboRenderableGroup = {\n axisIds: number[];\n categoryAxis: XlsxChartAxis | null;\n chartType: string;\n gapWidth?: number;\n is3d?: boolean;\n raw?: Record<string, unknown>;\n series: XlsxChartSeries[];\n valueAxis: XlsxChartAxis | null;\n};\n\ntype ChartStage = {\n color: string;\n isSubtotal: boolean;\n label: string;\n value: number;\n};\n\ntype BoxWhiskerStats = {\n lowerFence: number;\n lowerWhisker: number;\n max: number;\n mean: number;\n median: number;\n min: number;\n outliers: number[];\n q1: number;\n q3: number;\n upperFence: number;\n upperWhisker: number;\n visiblePoints: number[];\n};\n\ntype SurfaceDomain = {\n maxValue: number;\n minValue: number;\n safeMax: number;\n ticks: number[];\n};\n\nfunction parseRgbColor(color: string) {\n const match = /^#?([0-9a-f]{6})$/i.exec(color);\n if (!match) {\n return null;\n }\n return {\n blue: Number.parseInt(match[1].slice(4, 6), 16),\n green: Number.parseInt(match[1].slice(2, 4), 16),\n red: Number.parseInt(match[1].slice(0, 2), 16)\n };\n}\n\nfunction mixRgbColor(color: string, mixWith: string, ratio: number) {\n const base = parseRgbColor(color);\n const target = parseRgbColor(mixWith);\n if (!base || !target) {\n return color;\n }\n const clamped = Math.max(0, Math.min(1, ratio));\n const mixChannel = (left: number, right: number) => Math.round(left + (right - left) * clamped);\n return `#${[\n mixChannel(base.red, target.red),\n mixChannel(base.green, target.green),\n mixChannel(base.blue, target.blue)\n ].map((value) => value.toString(16).padStart(2, \"0\")).join(\"\")}`;\n}\n\nfunction lightenColor(color: string, ratio: number) {\n return mixRgbColor(color, \"#ffffff\", ratio);\n}\n\nfunction darkenColor(color: string, ratio: number) {\n return mixRgbColor(color, \"#000000\", ratio);\n}\n\nfunction clamp(value: number, min: number, max: number) {\n return Math.max(min, Math.min(max, value));\n}\n\nconst DEFAULT_CHART_FONT_STACK = [\n \"\\\"Aptos\\\"\",\n \"Calibri\",\n \"Carlito\",\n \"\\\"React XLSX Carlito\\\"\",\n \"\\\"Segoe UI\\\"\",\n \"Tahoma\",\n \"Arial\",\n \"sans-serif\"\n].join(\", \");\n\nconst DEFAULT_CHART_TEXT_COLOR = \"#000000\";\nconst DEFAULT_CHART_MUTED_TEXT_COLOR = \"#7f7f7f\";\n\nfunction escapeCssFontFamilyToken(value: string) {\n const trimmed = value.trim();\n if (!trimmed) {\n return \"\";\n }\n if (\n trimmed.startsWith(\"\\\"\")\n || trimmed.startsWith(\"'\")\n || /^(serif|sans-serif|monospace|cursive|fantasy|system-ui|math|emoji|fangsong)$/i.test(trimmed)\n ) {\n return trimmed;\n }\n return /\\s/.test(trimmed) ? `\"${trimmed.replace(/\"/g, \"\\\\\\\"\")}\"` : trimmed;\n}\n\nfunction buildChartFontFamily(fontFamily: string | undefined) {\n if (!fontFamily || fontFamily.trim().length === 0) {\n return DEFAULT_CHART_FONT_STACK;\n }\n const tokens = fontFamily\n .split(\",\")\n .map(escapeCssFontFamilyToken)\n .filter((token) => token.length > 0);\n if (tokens.length === 0) {\n return DEFAULT_CHART_FONT_STACK;\n }\n return [...tokens, \"Carlito\", \"\\\"React XLSX Carlito\\\"\", \"\\\"Segoe UI\\\"\", \"Tahoma\", \"Arial\", \"sans-serif\"].join(\", \");\n}\n\nfunction resolveChartTextColor(chart: XlsxChart) {\n return chart.textColor ?? chart.titleColor ?? DEFAULT_CHART_TEXT_COLOR;\n}\n\nfunction resolveChartAxisTextColor(chart: XlsxChart) {\n return chart.axisLabelColor ?? chart.textColor ?? chart.titleColor ?? DEFAULT_CHART_TEXT_COLOR;\n}\n\nfunction resolveChartMutedTextColor(chart: XlsxChart) {\n return chart.textColor ?? chart.axisLabelColor ?? DEFAULT_CHART_MUTED_TEXT_COLOR;\n}\n\nfunction safeNumber(value: unknown) {\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return value;\n }\n if (typeof value === \"string\") {\n const normalized = value.trim().replace(/,/g, \"\");\n if (!normalized) {\n return null;\n }\n const parsed = Number(normalized);\n return Number.isFinite(parsed) ? parsed : null;\n }\n return null;\n}\n\nfunction chartSeriesColor(chart: XlsxChart, seriesIndex: number) {\n const series = chart.series[seriesIndex];\n const paletteColor = chart.chartColorPalette?.[seriesIndex % Math.max(1, chart.chartColorPalette.length)];\n return series?.color ?? series?.lineColor ?? paletteColor ?? chart.textColor ?? \"#222222\";\n}\n\nfunction chartSeriesStrokeColor(chart: XlsxChart, seriesIndex: number) {\n const series = chart.series[seriesIndex];\n const paletteColor = chart.chartColorPalette?.[seriesIndex % Math.max(1, chart.chartColorPalette.length)];\n return series?.lineColor ?? series?.color ?? paletteColor ?? chart.textColor ?? \"#222222\";\n}\n\nfunction variesBarColorsByCategory(chart: XlsxChart) {\n return chart.series.length === 1\n && chart.varyColors !== false\n && !chart.chartExLayout\n && [\"ColumnClustered\", \"ColumnStacked\", \"ColumnPercentStacked\", \"BarClustered\", \"BarStacked\", \"BarPercentStacked\"].includes(chart.chartType);\n}\n\nfunction chartPointColor(chart: XlsxChart, pointIndex: number, seriesIndex = 0) {\n const pointStyle = chart.series[seriesIndex]?.dataPointStyles?.find((entry) => entry.index === pointIndex);\n if (pointStyle?.color) {\n return pointStyle.color;\n }\n const rawPoint = chart.series[seriesIndex]?.dataPoints?.[pointIndex];\n if (rawPoint && typeof rawPoint === \"object\") {\n const pointRecord = rawPoint as Record<string, unknown>;\n if (typeof pointRecord.color === \"string\") {\n return pointRecord.color;\n }\n if (typeof pointRecord.fillColor === \"string\") {\n return pointRecord.fillColor;\n }\n if (typeof pointRecord.solidFillHex === \"string\") {\n const normalized = pointRecord.solidFillHex.replace(/^#/, \"\");\n if (/^[0-9a-fA-F]{6}$/.test(normalized)) {\n return `#${normalized.toLowerCase()}`;\n }\n }\n const shapeProperties = pointRecord.shapeProperties && typeof pointRecord.shapeProperties === \"object\"\n ? pointRecord.shapeProperties as Record<string, unknown>\n : null;\n if (shapeProperties && typeof shapeProperties.solidFillHex === \"string\") {\n const normalized = shapeProperties.solidFillHex.replace(/^#/, \"\");\n if (/^[0-9a-fA-F]{6}$/.test(normalized)) {\n return `#${normalized.toLowerCase()}`;\n }\n }\n }\n const themeColors = chart.raw?.builtinThemeColors as Record<number, string> | undefined;\n const pointCount = Math.max(1, chart.series[seriesIndex]?.values.length ?? 0);\n const builtinColor = themeColors ? resolveBuiltinChartColor(getBuiltinChartColor(chart.chartStyleId, pointIndex, pointCount), themeColors) : undefined;\n if (builtinColor) return builtinColor;\n const palette = chart.chartColorPalette;\n if (palette && palette.length > 0) {\n const offset = chart.chartColorPaletteOffset ?? 0;\n return palette[(pointIndex + offset) % palette.length] ?? palette[pointIndex % palette.length];\n }\n return chartSeriesColor(chart, seriesIndex);\n}\n\nfunction isHistogramLikeSeries(series: XlsxChartSeries | null | undefined) {\n const raw = series?.raw && typeof series.raw === \"object\"\n ? series.raw as Record<string, unknown>\n : null;\n return Array.isArray(raw?.chartExHistogramBins) && raw.chartExHistogramBins.length > 0;\n}\n\nfunction isHistogramLikeChart(chart: XlsxChart) {\n return chart.series.some((series) => isHistogramLikeSeries(series));\n}\n\nfunction resolveRegionMapBaseColor(chart: XlsxChart, seriesIndex: number) {\n return chart.series[seriesIndex]?.color\n ?? chart.series[seriesIndex]?.lineColor\n ?? chart.chartColorPalette?.[0]\n ?? chartSeriesColor(chart, seriesIndex);\n}\n\nfunction resolveRegionMapDataColor(chart: XlsxChart, seriesIndex: number) {\n const pointColor = normalizeRendererHexColor(chartPointColor(chart, 0, seriesIndex));\n if (pointColor) {\n return pointColor;\n }\n\n const palette = Array.isArray(chart.chartColorPalette) ? chart.chartColorPalette : [];\n if (palette.length > 0) {\n const offset = chart.chartColorPaletteOffset ?? 0;\n const paletteColor = normalizeRendererHexColor(\n palette[((offset % palette.length) + palette.length) % palette.length]\n );\n if (paletteColor) {\n return paletteColor;\n }\n }\n\n return normalizeRendererHexColor(chart.series[seriesIndex]?.color ?? chart.series[seriesIndex]?.lineColor)\n ?? \"#4f81bd\";\n}\n\nfunction resolveRegionMapValueColors(series: XlsxChartSeries | null | undefined) {\n const raw = series?.raw && typeof series.raw === \"object\"\n ? series.raw as Record<string, unknown>\n : null;\n const colors = Array.isArray(raw?.valueColors)\n ? raw.valueColors\n .map((value) => normalizeRendererHexColor(value))\n .filter((value): value is string => Boolean(value))\n : [];\n return colors.length >= 2 ? colors : null;\n}\n\nfunction resolveRegionMapColorStrings(series: XlsxChartSeries | null | undefined) {\n const raw = series?.raw && typeof series.raw === \"object\"\n ? series.raw as Record<string, unknown>\n : null;\n const values = Array.isArray(raw?.chartExColorStrings)\n ? raw.chartExColorStrings\n .map((value) => (typeof value === \"string\" ? value.trim() : \"\"))\n : [];\n return values.some((value) => value.length > 0) ? values : null;\n}\n\nfunction resolveRegionMapLayoutProperties(series: XlsxChartSeries | null | undefined) {\n const raw = series?.raw && typeof series.raw === \"object\"\n ? series.raw as Record<string, unknown>\n : null;\n return raw?.layoutProperties && typeof raw.layoutProperties === \"object\"\n ? raw.layoutProperties as Record<string, unknown>\n : null;\n}\n\nfunction resolveRegionMapValueColorFromStops(stops: string[], ratio: number) {\n if (stops.length === 0) {\n return \"#4f81bd\";\n }\n if (stops.length === 1) {\n return stops[0];\n }\n const clamped = clamp(ratio, 0, 1);\n const scaled = clamped * (stops.length - 1);\n const lowerIndex = Math.floor(scaled);\n const upperIndex = Math.min(stops.length - 1, lowerIndex + 1);\n const mixRatio = scaled - lowerIndex;\n return mixRgbColor(stops[lowerIndex] ?? stops[0], stops[upperIndex] ?? stops[stops.length - 1], mixRatio);\n}\n\nfunction resolveRegionMapValueColor(chart: XlsxChart, seriesIndex: number, ratio: number) {\n const explicitStops = resolveRegionMapValueColors(chart.series[seriesIndex] ?? null);\n if (explicitStops) {\n return resolveRegionMapValueColorFromStops(explicitStops, ratio);\n }\n const baseColor = resolveRegionMapDataColor(chart, seriesIndex);\n return resolveRegionMapValueColorFromStops([\n lightenColor(baseColor, 0.82),\n lightenColor(baseColor, 0.28),\n darkenColor(baseColor, 0.08)\n ], ratio);\n}\n\nfunction resolveRegionMapNoDataColor(chart: XlsxChart, seriesIndex: number) {\n const baseColor = resolveRegionMapBaseColor(chart, seriesIndex);\n return normalizeRendererHexColor(baseColor) ?? chartSeriesColor(chart, seriesIndex);\n}\n\nfunction buildRegionMapLegendItems(chart: XlsxChart): LegendItem[] {\n const primarySeriesIndex = Math.max(0, chart.series.findIndex((series) => series.hidden !== true));\n const categoricalValues = resolveRegionMapColorStrings(chart.series[primarySeriesIndex] ?? null);\n if (categoricalValues) {\n const uniqueValues = Array.from(new Set(categoricalValues.filter(Boolean)));\n return uniqueValues.map((value, index) => ({\n color: chartPointColor(chart, index, primarySeriesIndex),\n label: value\n }));\n }\n const values = (chart.series[primarySeriesIndex]?.values ?? [])\n .map((value) => safeNumber(value))\n .filter((value): value is number => value != null);\n if (values.length === 0) {\n return [];\n }\n const minValue = Math.min(...values);\n const maxValue = Math.max(...values);\n return [minValue, maxValue].map((value, index) => ({\n color: resolveRegionMapValueColor(chart, primarySeriesIndex, index),\n label: formatTickValue(value)\n }));\n}\n\nfunction normalizeBuiltinPieStyleId(styleId: number | undefined) {\n if (typeof styleId !== \"number\" || !Number.isFinite(styleId)) {\n return null;\n }\n return styleId >= 100 ? styleId - 100 : styleId;\n}\n\nfunction getBuiltinPiePalette(chart: XlsxChart, seriesIndex: number) {\n if (chart.raw?.builtinThemeColors) return null;\n const normalized = normalizeBuiltinPieStyleId(chart.chartStyleId);\n if (normalized !== 32) {\n return null;\n }\n const baseColor = chart.series[seriesIndex]?.color\n ?? chart.series[seriesIndex]?.lineColor\n ?? chart.chartColorPalette?.[0]\n ?? null;\n if (!baseColor) {\n return null;\n }\n return [\n lightenColor(baseColor, 0.16),\n darkenColor(baseColor, 0.42),\n baseColor,\n darkenColor(baseColor, 0.18),\n lightenColor(baseColor, 0.08),\n darkenColor(baseColor, 0.3)\n ];\n}\n\nfunction resolvePiePointColor(chart: XlsxChart, pointIndex: number, seriesIndex = 0) {\n const pointStyle = chart.series[seriesIndex]?.dataPointStyles?.find((entry) => entry.index === pointIndex);\n if (pointStyle?.color) {\n return pointStyle.color;\n }\n const builtinPalette = getBuiltinPiePalette(chart, seriesIndex);\n if (builtinPalette && builtinPalette.length > 0) {\n return builtinPalette[pointIndex % builtinPalette.length] ?? builtinPalette[0];\n }\n return chartPointColor(chart, pointIndex, seriesIndex);\n}\n\nfunction selectPrimaryPieSeriesIndex(chart: XlsxChart) {\n let bestIndex = 0;\n let bestScore = Number.NEGATIVE_INFINITY;\n\n chart.series.forEach((series, index) => {\n let positiveCount = 0;\n let total = 0;\n for (const rawValue of series.values) {\n const value = safeNumber(rawValue);\n if (value != null && value > 0) {\n positiveCount += 1;\n total += value;\n }\n }\n const score = positiveCount * 1_000_000 + total;\n if (score > bestScore) {\n bestScore = score;\n bestIndex = index;\n }\n });\n\n return bestIndex;\n}\n\nfunction chartSeriesBarColors(\n chart: XlsxChart,\n seriesIndex: number,\n value: number,\n negativeFillMode: \"chartArea\" | \"none\" | \"series\"\n) {\n const series = chart.series[seriesIndex];\n const defaultFill = chartSeriesColor(chart, seriesIndex);\n const defaultStroke = chartSeriesStrokeColor(chart, seriesIndex);\n const defaultStrokeWidth = typeof series?.lineWidthPx === \"number\" && Number.isFinite(series.lineWidthPx)\n ? Math.max(0.8, Math.min(4, series.lineWidthPx))\n : 1;\n if (value < 0 && series?.invertIfNegative) {\n const resolvedNegativeFill = negativeFillMode === \"none\"\n ? \"none\"\n : series.negativeColor\n ?? (negativeFillMode === \"chartArea\" ? chart.chartAreaFillColor : undefined)\n ?? defaultFill;\n return {\n fill: resolvedNegativeFill,\n stroke: series.negativeLineColor ?? defaultStroke,\n strokeWidth: defaultStrokeWidth\n };\n }\n return {\n fill: defaultFill,\n stroke: defaultStroke,\n strokeWidth: defaultStrokeWidth\n };\n}\n\nfunction resolveCategoryBandPadding(gapWidth: number | undefined) {\n const normalizedGap = typeof gapWidth === \"number\" && Number.isFinite(gapWidth)\n ? clamp(gapWidth, 0, 500)\n : 150;\n const inner = clamp(normalizedGap / (100 + normalizedGap), 0.05, 0.88);\n const outer = clamp(inner * 0.5, 0, 0.45);\n return { inner, outer };\n}\n\nfunction normalizeLegendPosition(position: string | undefined) {\n switch (position) {\n case \"bottom\":\n return \"bottom\";\n case \"left\":\n return \"left\";\n case \"right\":\n return \"right\";\n case \"top\":\n return \"top\";\n case \"b\":\n return \"bottom\";\n case \"l\":\n return \"left\";\n case \"r\":\n return \"right\";\n case \"t\":\n return \"top\";\n default:\n return position;\n }\n}\n\nfunction normalizeChartMarkerSymbol(value: string | undefined) {\n if (!value || value === \"none\") {\n return \"none\";\n }\n if (value === \"auto\") {\n return \"circle\";\n }\n return value;\n}\n\nfunction normalizeRenderableChartType(chart: XlsxChart) {\n if (chart.chartType === \"ScatterSmooth\") {\n return \"ScatterSmooth\";\n }\n if (chart.chartType === \"Pie\" && chart.is3d) {\n return \"Pie3D\";\n }\n if (\n chart.chartType === \"Pie\"\n && chart.series.some((series) => Array.isArray(series.dataPoints) && series.dataPoints.some((point) => (\n point != null\n && typeof point === \"object\"\n && \"explosion\" in point\n && typeof (point as { explosion?: unknown }).explosion === \"number\"\n && ((point as { explosion?: number }).explosion ?? 0) > 0\n )))\n ) {\n return \"PieExploded\";\n }\n if (chart.chartType === \"Unsupported(c:ofPieChart)\") {\n return \"BarOfPie\";\n }\n return chart.chartType;\n}\n\nfunction normalizeCategoryLabel(value: unknown) {\n if (value == null) {\n return \"\";\n }\n return String(value)\n .replace(/[\\u200B-\\u200D\\uFEFF]/g, \"\")\n .trim();\n}\n\nfunction estimateReferencePointCount(formula: string | undefined) {\n if (!formula) {\n return 0;\n }\n const bang = formula.lastIndexOf(\"!\");\n const rawRange = (bang >= 0 ? formula.slice(bang + 1) : formula).replace(/\\$/g, \"\");\n const match = /^([A-Za-z]+)(\\d+):([A-Za-z]+)(\\d+)$/.exec(rawRange.trim());\n if (!match) {\n return 0;\n }\n const startRow = Number(match[2]);\n const endRow = Number(match[4]);\n if (!Number.isFinite(startRow) || !Number.isFinite(endRow)) {\n return 0;\n }\n return Math.abs(endRow - startRow) + 1;\n}\n\nfunction getCategoryLabels(chart: XlsxChart) {\n const primaryCategories = chart.series[0]?.categories ?? [];\n const includeReferenceCategoryCount = chart.plotVisibleOnly !== true;\n const referenceCategoryCount = includeReferenceCategoryCount\n ? Math.max(\n 0,\n ...chart.series.map((series) => Math.max(\n estimateReferencePointCount(series.categoriesRef?.formula),\n estimateReferencePointCount(series.valuesRef?.formula)\n ))\n )\n : 0;\n const categoryCount = Math.max(\n referenceCategoryCount,\n primaryCategories.length,\n ...chart.series.map((series) => Math.max(series.categories.length, series.values.length))\n );\n if (categoryCount <= 0) {\n return [];\n }\n const hasAnyExplicitCategory = chart.series.some((series) => (\n series.categories.some((value) => normalizeCategoryLabel(value).length > 0)\n ));\n const fallbackToImplicitOrdinal = chart.series.some((series) => {\n const categoriesLength = series.categories.length;\n if (categoriesLength === 0) {\n return false;\n }\n return series.categories.every((value) => normalizeCategoryLabel(value).length === 0);\n }) || !hasAnyExplicitCategory;\n return Array.from({ length: categoryCount }, (_, categoryIndex) => {\n const primary = primaryCategories[categoryIndex];\n if (primary != null) {\n const normalizedPrimary = normalizeCategoryLabel(primary);\n if (normalizedPrimary.length > 0) {\n return formatCategoryLabel(chart, primary, normalizedPrimary);\n }\n }\n const fallback = chart.series\n .map((series) => series.categories[categoryIndex])\n .find((value) => normalizeCategoryLabel(value).length > 0);\n if (fallback != null) {\n return formatCategoryLabel(chart, fallback, normalizeCategoryLabel(fallback));\n }\n return fallbackToImplicitOrdinal ? String(categoryIndex + 1) : \"\";\n });\n}\n\nfunction isComboChart(chart: XlsxChart) {\n const typeGroups = chart.typeGroups ?? [];\n if (typeGroups.length < 2) {\n return false;\n }\n const distinctChartTypes = new Set(typeGroups.map((group) => group.chartType));\n return distinctChartTypes.size > 1;\n}\n\nfunction getComboLegendSeries(chart: XlsxChart) {\n if (!isComboChart(chart)) {\n return chart.series.map((series, index) => ({\n color: chartSeriesColor(chart, index),\n label: series.name ?? `Series ${index + 1}`\n }));\n }\n return (chart.typeGroups ?? []).flatMap((group) => (\n group.series.map((series, seriesIndex) => ({\n color: series.lineColor ?? series.markerColor ?? series.color ?? chartSeriesColor(chart, seriesIndex),\n label: series.name ?? `Series ${seriesIndex + 1}`\n }))\n ));\n}\n\nfunction findAxisForGroup(\n chart: XlsxChart,\n axisIds: number[],\n positionMatcher: (position: string | undefined) => boolean,\n allowAnyMatch = false\n) {\n const positionedMatch = chart.axes.find((axis) => (\n axis.id != null\n && axisIds.includes(axis.id)\n && positionMatcher(axis.position)\n ));\n if (positionedMatch) {\n return positionedMatch;\n }\n if (!allowAnyMatch) {\n return null;\n }\n return chart.axes.find((axis) => axis.id != null && axisIds.includes(axis.id)) ?? null;\n}\n\nfunction buildComboGroups(chart: XlsxChart): ComboRenderableGroup[] {\n return (chart.typeGroups ?? []).map((group) => {\n const axisIds = group.axisIds ?? [];\n const categoryAxis = findAxisForGroup(chart, axisIds, (position) => position === \"b\" || position === \"t\")\n ?? chart.categoryAxis\n ?? null;\n const valueAxis = findAxisForGroup(chart, axisIds, (position) => position === \"l\" || position === \"r\", true)\n ?? chart.valueAxis\n ?? null;\n return {\n axisIds,\n categoryAxis,\n chartType: group.chartType,\n gapWidth: group.gapWidth,\n is3d: group.is3d,\n raw: group.raw,\n series: group.series,\n valueAxis\n };\n }).filter((group) => group.series.length > 0);\n}\n\nfunction resolveRenderableSeriesValue(rawValue: unknown, displayBlanksAs: string | undefined) {\n const numeric = safeNumber(rawValue);\n if (numeric != null) {\n return numeric;\n }\n return displayBlanksAs === \"zero\" ? 0 : null;\n}\n\nfunction coerceLooseNumber(value: unknown): number | null {\n const strict = safeNumber(value);\n if (strict != null) {\n return strict;\n }\n if (Array.isArray(value)) {\n for (const entry of value) {\n const nested = coerceLooseNumber(entry);\n if (nested != null) {\n return nested;\n }\n }\n return null;\n }\n if (value && typeof value === \"object\") {\n const record = value as Record<string, unknown>;\n for (const key of [\"x\", \"value\", \"v\", \"num\", \"number\", \"raw\"]) {\n const nested = coerceLooseNumber(record[key]);\n if (nested != null) {\n return nested;\n }\n }\n return null;\n }\n if (typeof value === \"string\") {\n const match = /-?\\d+(?:\\.\\d+)?/.exec(value);\n if (!match) {\n return null;\n }\n const parsed = Number(match[0]);\n return Number.isFinite(parsed) ? parsed : null;\n }\n return null;\n}\n\nfunction buildPieEntries(chart: XlsxChart, seriesIndex = selectPrimaryPieSeriesIndex(chart)) {\n const categories = getCategoryLabels(chart);\n const values = chart.series[seriesIndex]?.values ?? [];\n return values\n .map((rawValue, index) => ({\n color: resolvePiePointColor(chart, index, seriesIndex),\n index,\n label: normalizeCategoryLabel(categories[index]),\n value: Math.max(0, safeNumber(rawValue) ?? 0)\n }))\n .filter((entry) => entry.value > 0);\n}\n\nfunction resolveChartStageSubtotal(series: XlsxChart[\"series\"][number]) {\n const raw = series.raw && typeof series.raw === \"object\"\n ? series.raw as Record<string, unknown>\n : null;\n const layoutProperties = raw?.layoutProperties && typeof raw.layoutProperties === \"object\"\n ? raw.layoutProperties as Record<string, unknown>\n : null;\n const subtotals = Array.isArray(layoutProperties?.subtotals) ? layoutProperties.subtotals : [];\n return subtotals.length > 0 || layoutProperties?.aggregation === true;\n}\n\nfunction buildChartStages(chart: XlsxChart) {\n if (chart.chartType === \"Funnel\" || chart.chartType === \"Waterfall\") {\n const primarySeriesIndex = Math.max(0, chart.series.findIndex((series) => series.hidden !== true));\n const primarySeries = chart.series[primarySeriesIndex] ?? null;\n if (!primarySeries) {\n return [];\n }\n\n const labels = getCategoryLabels(chart);\n return primarySeries.values\n .map((rawValue, index): ChartStage | null => {\n const value = safeNumber(rawValue);\n if (value == null || !Number.isFinite(value)) {\n return null;\n }\n return {\n color: chart.varyColors\n ? chartPointColor(chart, index, primarySeriesIndex)\n : chartSeriesColor(chart, primarySeriesIndex),\n isSubtotal: false,\n label: normalizeCategoryLabel(labels[index]) || String(index + 1),\n value\n };\n })\n .filter((stage): stage is ChartStage => stage != null);\n }\n\n return chart.series\n .map((series, index): ChartStage | null => {\n const value = series.values.reduce<number>((sum, entry) => sum + (safeNumber(entry) ?? 0), 0);\n if (!Number.isFinite(value)) {\n return null;\n }\n const formula = typeof series.valuesRef?.formula === \"string\" ? series.valuesRef.formula : \"\";\n const label = series.name\n ?? (formula.length > 0 ? formula.replace(/^.*!/, \"\").replace(/\\$/g, \"\") : `Series ${index + 1}`);\n return {\n color: chartSeriesColor(chart, typeof series.formatIdx === \"number\" ? series.formatIdx : index),\n isSubtotal: resolveChartStageSubtotal(series),\n label,\n value\n };\n })\n .filter((stage): stage is ChartStage => stage != null);\n}\n\nfunction buildHierarchyData(chart: XlsxChart) {\n const root: ChartHierarchyDatum = {\n children: [],\n name: chart.title ?? chart.name ?? \"Root\"\n };\n const rootChildren = root.children ?? [];\n const topLevelIndexByName = new Map<string, number>();\n const primaryHierarchySeries = chart.series.find((series) => {\n const raw = series.raw && typeof series.raw === \"object\" ? series.raw as Record<string, unknown> : null;\n return Array.isArray(raw?.chartExHierarchyCategories);\n }) ?? null;\n const primaryHierarchyPaths = (() => {\n if (!primaryHierarchySeries) {\n return null;\n }\n const raw = primaryHierarchySeries.raw as Record<string, unknown>;\n return Array.isArray(raw.chartExHierarchyCategories)\n ? raw.chartExHierarchyCategories.map((entry) => Array.isArray(entry)\n ? entry.map((value) => normalizeCategoryLabel(value)).filter((value) => value.length > 0)\n : [])\n : null;\n })();\n const rowCount = primaryHierarchyPaths\n ? primaryHierarchyPaths.length\n : Math.max(0, ...chart.series.map((series) => series.values.length));\n\n for (let rowIndex = 0; rowIndex < rowCount; rowIndex += 1) {\n const path = primaryHierarchyPaths?.[rowIndex] ?? chart.series\n .map((series) => normalizeCategoryLabel(series.categories[rowIndex] ?? series.values[rowIndex]))\n .filter((value) => value.length > 0);\n if (path.length === 0) {\n continue;\n }\n\n let current = root;\n path.forEach((part, levelIndex) => {\n current.children = current.children ?? [];\n const preserveDuplicateLeaf = levelIndex === path.length - 1 && path.length === 1;\n let next = preserveDuplicateLeaf\n ? undefined\n : current.children.find((child) => child.name === part);\n if (!next) {\n next = { children: [], name: part };\n if (levelIndex === 0) {\n const topLevelIndex = topLevelIndexByName.size;\n topLevelIndexByName.set(part, topLevelIndex);\n next.colorIndex = topLevelIndex;\n } else {\n next.colorIndex = current.colorIndex;\n }\n current.children.push(next);\n }\n current = next;\n });\n\n const valueSource = primaryHierarchySeries ?? chart.series[chart.series.length - 1] ?? null;\n current.value = (current.value ?? 0) + Math.max(0.0001, safeNumber(valueSource?.values[rowIndex]) ?? 1);\n }\n\n return rootChildren.length > 0 ? root : null;\n}\n\nfunction resolveBoxWhiskerQuartileMethod(series: XlsxChartSeries) {\n const raw = series.raw && typeof series.raw === \"object\" ? series.raw as Record<string, unknown> : null;\n const layoutProperties = raw?.layoutProperties && typeof raw.layoutProperties === \"object\"\n ? raw.layoutProperties as Record<string, unknown>\n : null;\n const statistics = layoutProperties?.statistics && typeof layoutProperties.statistics === \"object\"\n ? layoutProperties.statistics as Record<string, unknown>\n : null;\n return statistics?.quartileMethod === \"inclusive\" ? \"inclusive\" : \"exclusive\";\n}\n\nfunction resolveBoxWhiskerVisibility(series: XlsxChartSeries) {\n const raw = series.raw && typeof series.raw === \"object\" ? series.raw as Record<string, unknown> : null;\n const layoutProperties = raw?.layoutProperties && typeof raw.layoutProperties === \"object\"\n ? raw.layoutProperties as Record<string, unknown>\n : null;\n const visibility = layoutProperties?.visibility && typeof layoutProperties.visibility === \"object\"\n ? layoutProperties.visibility as Record<string, unknown>\n : null;\n return {\n meanLine: visibility?.meanLine === true,\n meanMarker: visibility?.meanMarker !== false,\n nonoutliers: visibility?.nonoutliers === true,\n outliers: visibility?.outliers !== false\n };\n}\n\nfunction computePercentile(sortedValues: number[], percentile: number, method: \"exclusive\" | \"inclusive\") {\n const count = sortedValues.length;\n if (count === 0) {\n return 0;\n }\n if (count === 1) {\n return sortedValues[0] ?? 0;\n }\n\n const rank = method === \"exclusive\"\n ? percentile * (count + 1)\n : 1 + percentile * (count - 1);\n if (rank <= 1) {\n return sortedValues[0] ?? 0;\n }\n if (rank >= count) {\n return sortedValues[count - 1] ?? 0;\n }\n\n const lowerIndex = Math.floor(rank) - 1;\n const upperIndex = Math.ceil(rank) - 1;\n const fraction = rank - Math.floor(rank);\n const lower = sortedValues[Math.max(0, lowerIndex)] ?? sortedValues[0] ?? 0;\n const upper = sortedValues[Math.max(0, upperIndex)] ?? sortedValues[count - 1] ?? 0;\n return lower + (upper - lower) * fraction;\n}\n\nfunction computeBoxWhiskerStats(series: XlsxChartSeries): BoxWhiskerStats | null {\n const sortedValues = series.values\n .map((value) => safeNumber(value))\n .filter((value): value is number => value != null)\n .sort((left, right) => left - right);\n if (sortedValues.length === 0) {\n return null;\n }\n\n const quartileMethod = resolveBoxWhiskerQuartileMethod(series);\n const q1 = computePercentile(sortedValues, 0.25, quartileMethod);\n const median = computePercentile(sortedValues, 0.5, quartileMethod);\n const q3 = computePercentile(sortedValues, 0.75, quartileMethod);\n const iqr = q3 - q1;\n const lowerFence = q1 - iqr * 1.5;\n const upperFence = q3 + iqr * 1.5;\n const visiblePoints = sortedValues.filter((value) => value >= lowerFence && value <= upperFence);\n const outliers = sortedValues.filter((value) => value < lowerFence || value > upperFence);\n const lowerWhisker = visiblePoints[0] ?? sortedValues[0] ?? 0;\n const upperWhisker = visiblePoints[visiblePoints.length - 1] ?? sortedValues[sortedValues.length - 1] ?? 0;\n const mean = sortedValues.reduce((sum, value) => sum + value, 0) / sortedValues.length;\n\n return {\n lowerFence,\n lowerWhisker,\n max: sortedValues[sortedValues.length - 1] ?? 0,\n mean,\n median,\n min: sortedValues[0] ?? 0,\n outliers,\n q1,\n q3,\n upperFence,\n upperWhisker,\n visiblePoints\n };\n}\n\nfunction resolveHierarchyNodeColor(chart: XlsxChart, node: HierarchyNode<ChartHierarchyDatum>) {\n const lineage = node.ancestors().reverse();\n const topLevel = lineage[1];\n const baseIndex = topLevel?.data.colorIndex ?? 0;\n const baseColor = chartSeriesColor(chart, baseIndex);\n const depth = Math.max(0, node.depth - 1);\n return depth === 0 ? baseColor : lightenColor(baseColor, clamp(depth * 0.16, 0, 0.5));\n}\n\nfunction resolveTreemapNodeColor(chart: XlsxChart, node: HierarchyNode<ChartHierarchyDatum>) {\n const lineage = node.ancestors().reverse();\n const topLevel = lineage[1];\n return chartSeriesColor(chart, topLevel?.data.colorIndex ?? 0);\n}\n\nfunction excelTreemapTile(node: HierarchyRectangularNode<ChartHierarchyDatum>, x0: number, y0: number, x1: number, y1: number) {\n if (!node.children || node.children.length === 0) {\n return;\n }\n if (node.depth === 0) {\n treemapDice(node, x0, y0, x1, y1);\n node.children.forEach((child) => excelTreemapTile(child, child.x0, child.y0, child.x1, child.y1));\n return;\n }\n treemapBinary(node, x0, y0, x1, y1);\n node.children.forEach((child) => excelTreemapTile(child, child.x0, child.y0, child.x1, child.y1));\n}\n\nfunction resolveSurfaceBaseColor(chart: XlsxChart, palette: Pick<ChartRendererPalette, \"text\">) {\n return chart.chartColorPalette?.[0]\n ?? chart.series[0]?.color\n ?? chart.series[0]?.lineColor\n ?? chart.axisLineColor\n ?? chart.textColor\n ?? palette.text;\n}\n\nfunction resolveExplicitSurfaceSeriesColor(chart: XlsxChart, kind: \"fill\" | \"line\") {\n const shape = chart.series[0]?.shapeProperties;\n if (kind === \"fill\" ? shape?.xmlFillHidden === true : shape?.xmlLineHidden === true) return \"transparent\";\n const color = kind === \"fill\"\n ? shape?.xmlFillColor ?? shape?.solidFillHex\n : shape?.xmlLineColor ?? shape?.lineColorHex;\n return normalizeRendererHexColor(color);\n}\n\nfunction getSurfaceColorStops(chart: XlsxChart, palette: ChartRendererPalette) {\n const explicitFill = resolveExplicitSurfaceSeriesColor(chart, \"fill\");\n if (explicitFill) return [explicitFill];\n const colors = (chart.chartColorPalette ?? []).filter((value): value is string => typeof value === \"string\" && value.length > 0);\n return colors.length > 0 ? colors : [resolveSurfaceBaseColor(chart, palette)];\n}\n\nfunction resolveSurfaceBandPaletteColor(chart: XlsxChart, palette: ChartRendererPalette, domain: SurfaceDomain, value: number) {\n const bandIndex = resolveSurfaceBandIndex(domain, value);\n const explicitColor = resolveSurfaceBandFormatColor(chart, \"bandFormatColors\", bandIndex);\n if (explicitColor) return explicitColor;\n const explicitFill = resolveExplicitSurfaceSeriesColor(chart, \"fill\");\n if (explicitFill) return explicitFill;\n const themeColors = chart.raw?.builtinThemeColors as Record<number, string> | undefined;\n const paletteCount = Math.trunc((domain.safeMax - domain.minValue) / (domain.ticks[1] - domain.ticks[0])) + 1;\n const builtinColor = themeColors ? resolveBuiltinChartColor(getBuiltinChartColor(chart.chartStyleId, bandIndex % paletteCount, paletteCount), themeColors) : undefined;\n if (builtinColor) return builtinColor;\n const stops = getSurfaceColorStops(chart, palette);\n if (stops.length === 0) {\n return resolveSurfaceBaseColor(chart, palette);\n }\n return stops[Math.min(stops.length - 1, Math.max(0, bandIndex))] ?? stops[stops.length - 1] ?? resolveSurfaceBaseColor(chart, palette);\n}\n\nfunction getSurfaceDomain(chart: XlsxChart): SurfaceDomain | null {\n const numericValues = chart.series.flatMap((series) => (\n series.values\n .map((value) => safeNumber(value))\n .filter((value): value is number => value != null)\n ));\n if (numericValues.length === 0) {\n return null;\n }\n const explicitMin = typeof chart.valueAxis?.min === \"number\" && Number.isFinite(chart.valueAxis.min)\n ? chart.valueAxis.min\n : null;\n const explicitMax = typeof chart.valueAxis?.max === \"number\" && Number.isFinite(chart.valueAxis.max)\n ? chart.valueAxis.max\n : null;\n const rawMin = Math.min(...numericValues);\n const rawMax = Math.max(...numericValues);\n const spanBase = Math.max(1e-6, rawMax - Math.min(0, rawMin));\n const roughStep = spanBase / 5;\n const magnitude = 10 ** Math.floor(Math.log10(Math.max(roughStep, 1e-6)));\n const normalized = roughStep / magnitude;\n const niceNormalized = normalized <= 1 ? 1 : normalized <= 2 ? 2 : normalized <= 5 ? 5 : 10;\n const step = typeof chart.valueAxis?.majorUnit === \"number\" && chart.valueAxis.majorUnit > 0\n ? chart.valueAxis.majorUnit\n : niceNormalized * magnitude;\n const minValue = explicitMin ?? (rawMin >= 0 ? 0 : Math.floor(rawMin / step) * step);\n const maxValue = explicitMax ?? Math.ceil(rawMax / step) * step;\n const safeMax = maxValue <= minValue ? minValue + step : maxValue;\n const ticks: number[] = [];\n for (let current = minValue; current <= safeMax + step * 0.001; current += step) {\n ticks.push(Number(current.toFixed(8)));\n }\n const boundedTicks = [...new Set([...ticks.filter((tick) => tick < safeMax), safeMax])];\n return {\n maxValue,\n minValue,\n safeMax,\n ticks: boundedTicks.length >= 2 ? boundedTicks : [minValue, safeMax]\n };\n}\n\nfunction resolveSurfaceBandColor(chart: XlsxChart, palette: ChartRendererPalette, domain: SurfaceDomain, value: number) {\n return resolveSurfaceBandPaletteColor(chart, palette, domain, value);\n}\n\nfunction resolveSurfaceBandIndex(domain: SurfaceDomain, value: number) {\n const ticks = domain.ticks;\n for (let index = 0; index < ticks.length - 1; index += 1) {\n const end = ticks[index + 1] ?? domain.safeMax;\n if (value <= end || index === ticks.length - 2) {\n return index;\n }\n }\n return Math.max(0, ticks.length - 2);\n}\n\nfunction resolveSurfaceBandFormatColor(chart: XlsxChart, key: \"bandFormatColors\" | \"bandFormatLineColors\", index: number) {\n const colors = chart.raw?.[key];\n if (!colors || typeof colors !== \"object\" || !Object.prototype.hasOwnProperty.call(colors, index)) return null;\n const color = (colors as Record<number, unknown>)[index];\n return typeof color === \"string\" && color.length > 0 ? color : null;\n}\n\nfunction resolveSurfaceWireframeColor(chart: XlsxChart, palette: ChartRendererPalette, domain: SurfaceDomain, value: number) {\n const bandIndex = resolveSurfaceBandIndex(domain, value);\n const themeColors = chart.raw?.builtinThemeColors as Record<number, string> | undefined;\n const paletteCount = Math.trunc((domain.safeMax - domain.minValue) / (domain.ticks[1] - domain.ticks[0])) + 1;\n const builtinLine = themeColors ? resolveBuiltinChartColor(getBuiltinChartSurfaceLine(chart.chartStyleId, bandIndex, paletteCount), themeColors) : undefined;\n return resolveSurfaceBandFormatColor(chart, \"bandFormatLineColors\", bandIndex)\n ?? resolveExplicitSurfaceSeriesColor(chart, \"line\")\n ?? builtinLine\n ?? resolveSurfaceBandPaletteColor(chart, palette, domain, value);\n}\n\nfunction resolveSurfacePlotRect(chart: XlsxChart, layout: ChartLayout) {\n if (!isContourSurfaceChart(chart)) {\n return layout.plot;\n }\n const columnCount = Math.max(1, getCategoryLabels(chart).length);\n const depthScale = Math.max(0.01, (chart.view3d?.depthPercent ?? 100) / 100);\n const targetAspect = columnCount / Math.max(1, chart.series.length) / depthScale;\n let width = layout.plot.width;\n let height = layout.plot.height;\n if (width / Math.max(1e-6, height) > targetAspect) {\n width = height * targetAspect;\n } else {\n height = width / Math.max(1e-6, targetAspect);\n }\n return {\n height,\n left: layout.plot.left + (layout.plot.width - width) / 2,\n top: layout.plot.top + (layout.plot.height - height) / 2,\n width\n };\n}\n\nfunction buildSurfaceLegendItems(chart: XlsxChart, palette: ChartRendererPalette) {\n const domain = getSurfaceDomain(chart);\n if (!domain) {\n return [];\n }\n const items: LegendItem[] = [];\n for (let index = 0; index < domain.ticks.length - 1; index += 1) {\n const start = domain.ticks[index] ?? domain.minValue;\n const end = domain.ticks[index + 1] ?? domain.safeMax;\n const midpoint = start + (end - start) * 0.5;\n items.push({\n color: chart.wireframe\n ? resolveSurfaceWireframeColor(chart, palette, domain, midpoint)\n : resolveSurfaceBandColor(chart, palette, domain, midpoint),\n label: `${formatTickValue(start)}-${formatTickValue(end)}`\n });\n }\n return items.reverse();\n}\n\nfunction isContourSurfaceChart(chart: XlsxChart) {\n const rawChartType = chart.raw && typeof chart.raw === \"object\" && typeof (chart.raw as Record<string, unknown>).xmlChartType === \"string\"\n ? (chart.raw as Record<string, unknown>).xmlChartType\n : \"\";\n if (rawChartType === \"surfaceChart\") {\n return true;\n }\n if (rawChartType === \"surface3DChart\") {\n return false;\n }\n return chart.chartType === \"Surface\" && chart.is3d !== true;\n}\n\nfunction renderSurfaceAxes(chart: XlsxChart, layout: ChartLayout) {\n if (chart.categoryAxis?.delete && chart.seriesAxis?.delete && chart.valueAxis?.delete) {\n return null;\n }\n const plot = resolveSurfacePlotRect(chart, layout);\n const categories = getCategoryLabels(chart);\n const seriesLabels = chart.series.map((series, index) => normalizeCategoryLabel(series.name) || `Q${index + 1}`);\n const labelColor = resolveChartAxisTextColor(chart);\n const axisColor = chart.axisLineColor ?? chart.chartAreaBorderColor ?? \"#888888\";\n const rowCount = Math.max(1, seriesLabels.length);\n const columnCount = Math.max(1, categories.length);\n const columnPositions = categories.map((_, index) => (\n plot.left + (isContourSurfaceChart(chart) && chart.valueAxis?.crossBetween !== \"midCat\"\n ? ((index + 0.5) / columnCount) * plot.width\n : (columnCount <= 1 ? plot.width / 2 : (index / (columnCount - 1)) * plot.width))\n ));\n const rowPositions = seriesLabels.map((_, index) => (\n plot.top + plot.height - (rowCount <= 1 ? plot.height / 2 : (index / (rowCount - 1)) * plot.height)\n ));\n\n return (\n <g>\n {isContourSurfaceChart(chart) && <rect\n fill=\"none\"\n height={plot.height}\n stroke={lightenColor(axisColor, 0.18)}\n strokeWidth={0.8}\n width={plot.width}\n x={plot.left}\n y={plot.top}\n />}\n {chart.categoryAxis?.delete !== true && chart.categoryAxis?.labelPosition !== \"none\" && categories.map((label, index) => (\n <text\n key={`surface-x-label-${index}`}\n fill={labelColor}\n fontSize={10}\n textAnchor=\"middle\"\n x={columnPositions[index] ?? plot.left}\n y={plot.top + plot.height + 14}\n >\n {label}\n </text>\n ))}\n {chart.seriesAxis?.delete !== true && chart.seriesAxis?.labelPosition !== \"none\" && seriesLabels.map((label, index) => (\n <text\n key={`surface-y-label-${index}`}\n fill={labelColor}\n fontSize={10}\n textAnchor=\"start\"\n x={plot.left + plot.width + 8}\n y={(rowPositions[index] ?? plot.top) + 3}\n >\n {label}\n </text>\n ))}\n </g>\n );\n}\n\nfunction normalizeRendererHexColor(value: unknown) {\n if (typeof value !== \"string\") {\n return null;\n }\n const trimmed = value.trim();\n if (!trimmed) {\n return null;\n }\n const normalized = trimmed.startsWith(\"#\") ? trimmed.slice(1) : trimmed;\n return /^[0-9a-f]{6}$/i.test(normalized) ? `#${normalized.toLowerCase()}` : null;\n}\n\nfunction buildStockLegendItems(chart: XlsxChart, _palette: ChartRendererPalette): LegendItem[] {\n return chart.series.map((series, index) => ({\n color: chartSeriesStrokeColor(chart, index),\n label: series.name ?? `Series ${index + 1}`\n }));\n}\n\nfunction getLegendItems(chart: XlsxChart, chartType: string, palette: ChartRendererPalette): LegendItem[] {\n if (!chart.legend) {\n return [];\n }\n if (isComboChart(chart)) {\n return getComboLegendSeries(chart);\n }\n if (chartType === \"Stock\") {\n return buildStockLegendItems(chart, palette);\n }\n if (chartType === \"Surface\") {\n return buildSurfaceLegendItems(chart, palette);\n }\n if (chartType === \"RegionMap\") {\n return buildRegionMapLegendItems(chart);\n }\n if (variesBarColorsByCategory(chart)) {\n return getCategoryLabels(chart).map((label, index) => ({\n color: chartPointColor(chart, index),\n label\n }));\n }\n if (chartType === \"Sunburst\" || chartType === \"Treemap\") {\n const hierarchyData = buildHierarchyData(chart);\n if (!hierarchyData?.children) {\n return [];\n }\n return hierarchyData.children.map((child, index) => ({\n color: chartSeriesColor(chart, child.colorIndex ?? index),\n label: child.name\n }));\n }\n if (chartType === \"Pie\" || chartType === \"Pie3D\" || chartType === \"PieExploded\" || chartType === \"Doughnut\" || chartType === \"BarOfPie\") {\n if (chartType === \"BarOfPie\") {\n const categories = getCategoryLabels(chart);\n const values = chart.series[0]?.values ?? [];\n return categories\n .map((label, index) => ({\n color: chartPointColor(chart, index),\n label: normalizeCategoryLabel(label),\n value: safeNumber(values[index]) ?? 0\n }))\n .filter((entry) => entry.value > 0 && entry.label.trim().length > 0)\n .map((entry) => ({\n color: entry.color,\n label: entry.label\n }));\n }\n return buildPieEntries(chart).map((entry) => ({\n color: entry.color,\n label: entry.label\n }));\n }\n const isXyLegend = (\n chartType === \"Scatter\"\n || chartType === \"ScatterLines\"\n || chartType === \"ScatterSmooth\"\n || chartType === \"Bubble\"\n );\n return chart.series.map((series, index) => ({\n color: isXyLegend\n ? (series.lineColor ?? series.markerColor ?? series.color ?? chartSeriesColor(chart, index))\n : chartSeriesColor(chart, index),\n label: series.name ?? `Series ${index + 1}`\n }));\n}\n\nfunction buildLayout(chart: XlsxChart, rect: XlsxImageRect, legendItems: LegendItem[]): ChartLayout {\n const width = Math.max(80, Math.round(rect.width));\n const height = Math.max(60, Math.round(rect.height));\n const isSurfaceChart = chart.chartType === \"Surface\"\n || (chart.raw && typeof chart.raw === \"object\" && typeof (chart.raw as Record<string, unknown>).xmlChartType === \"string\" && String((chart.raw as Record<string, unknown>).xmlChartType).includes(\"surface\"));\n const titleHeight = chart.title && !(isSurfaceChart && chart.raw?.titleOverlay === true) ? (isSurfaceChart ? 30 : 24) : 8;\n const legendPosition = normalizeLegendPosition(chart.legend?.position);\n\n const legendVertical = legendItems.length > 0 && (legendPosition === \"right\" || legendPosition === \"left\");\n const compactWidth = width <= 280;\n const compactHeight = height <= 200;\n const finalLegendPosition = compactWidth || compactHeight\n ? (legendVertical ? \"bottom\" : legendPosition)\n : legendPosition;\n const layoutLegendPosition = chart.chartType === \"RegionMap\" ? finalLegendPosition : legendPosition;\n const primarySeries = chart.series.find((series) => series.hidden !== true) ?? chart.series[0];\n const horizontalMapGradient = chart.chartType === \"RegionMap\"\n && legendItems.length > 0 && !resolveRegionMapColorStrings(primarySeries)\n && (layoutLegendPosition === \"top\" || layoutLegendPosition === \"bottom\");\n const horizontalLegendHeight = horizontalMapGradient\n ? Math.min(48, Math.max(24, height - titleHeight - 8))\n : 24;\n const legendWidth = isSurfaceChart ? Math.max(32, ...legendItems.map((item) => 20 + item.label.length * 5.4)) : 98;\n const plotLeft = (isSurfaceChart && chart.valueAxis?.delete ? 12 : 42) + (layoutLegendPosition === \"left\" ? legendWidth : 0);\n const plotRight = 16 + (layoutLegendPosition === \"right\" ? legendWidth : 0);\n const plotTop = titleHeight + (layoutLegendPosition === \"top\" ? horizontalLegendHeight : 0);\n const plotBottom = (horizontalMapGradient || (isSurfaceChart && chart.categoryAxis?.delete) ? 8 : 28) + (layoutLegendPosition === \"bottom\" ? horizontalLegendHeight : 0);\n const plotWidth = Math.max(horizontalMapGradient ? 1 : 40, width - plotLeft - plotRight);\n\n return {\n height,\n legendBounds: horizontalMapGradient ? {\n left: plotLeft,\n top: layoutLegendPosition === \"top\" ? titleHeight : height - horizontalLegendHeight,\n width: plotWidth,\n height: horizontalLegendHeight\n } : undefined,\n legendItems,\n legendPosition: finalLegendPosition,\n plot: {\n height: Math.max(horizontalMapGradient ? 1 : 40, height - plotTop - plotBottom),\n left: plotLeft,\n top: plotTop,\n width: plotWidth\n },\n titleHeight,\n width\n };\n}\n\nfunction buildNiceStep(minValue: number, maxValue: number, preferredTicks = 5) {\n const span = Math.max(1e-6, maxValue - minValue);\n const roughStep = span / Math.max(1, preferredTicks);\n const magnitude = 10 ** Math.floor(Math.log10(roughStep));\n const normalized = roughStep / magnitude;\n const niceNormalized = normalized <= 1 ? 1 : normalized <= 2 ? 2 : normalized <= 5 ? 5 : 10;\n return niceNormalized * magnitude;\n}\n\nfunction buildNumericTickValues(minValue: number, maxValue: number, majorUnit?: number) {\n if (!Number.isFinite(minValue) || !Number.isFinite(maxValue) || maxValue <= minValue) {\n return [];\n }\n const step = typeof majorUnit === \"number\" && majorUnit > 0\n ? majorUnit\n : buildNiceStep(minValue, maxValue, 5);\n if (!Number.isFinite(step) || step <= 0) {\n return [];\n }\n const start = Math.floor(minValue / step) * step;\n const values: number[] = [];\n for (let current = start; current <= maxValue + step * 0.001; current += step) {\n if (current >= minValue - step * 0.001 && current <= maxValue + step * 0.001) {\n values.push(Number(current.toFixed(8)));\n }\n }\n return values;\n}\n\nfunction resolveNumericAxisDomain(minValue: number, maxValue: number, majorUnit?: number, includeZero = false) {\n if (!Number.isFinite(minValue) || !Number.isFinite(maxValue)) {\n return {\n max: 1,\n min: 0,\n ticks: [0, 1]\n };\n }\n let domainMin = includeZero ? Math.min(0, minValue) : minValue;\n let domainMax = includeZero ? Math.max(0, maxValue) : maxValue;\n if (domainMax <= domainMin) {\n domainMax = domainMin + 1;\n }\n const step = typeof majorUnit === \"number\" && majorUnit > 0\n ? majorUnit\n : buildNiceStep(domainMin, domainMax, 5);\n const roundedMin = typeof majorUnit === \"number\" && majorUnit > 0\n ? domainMin\n : Math.floor(domainMin / step) * step;\n const roundedMax = typeof majorUnit === \"number\" && majorUnit > 0\n ? domainMax\n : Math.ceil(domainMax / step) * step;\n const finalMin = includeZero ? Math.min(0, roundedMin) : roundedMin;\n const finalMax = roundedMax <= finalMin ? finalMin + step : roundedMax;\n const ticks = buildNumericTickValues(finalMin, finalMax, step);\n return {\n max: finalMax,\n min: finalMin,\n ticks: ticks.length > 0 ? ticks : [finalMin, finalMax]\n };\n}\n\nfunction resolveAxisDomainWithChartOverrides(\n axis: XlsxChartAxis | null | undefined,\n minValue: number,\n maxValue: number,\n includeZero = false\n) {\n const hasExplicitMin = typeof axis?.min === \"number\" && Number.isFinite(axis.min);\n const hasExplicitMax = typeof axis?.max === \"number\" && Number.isFinite(axis.max);\n const rawMin = hasExplicitMin ? Number(axis?.min) : minValue;\n const rawMax = hasExplicitMax ? Number(axis?.max) : maxValue;\n const domain = resolveNumericAxisDomain(rawMin, rawMax, axis?.majorUnit, includeZero);\n return {\n hasExplicitMax,\n hasExplicitMin,\n majorUnit: axis?.majorUnit,\n max: hasExplicitMax ? Number(axis?.max) : domain.max,\n min: hasExplicitMin ? Number(axis?.min) : domain.min,\n ticks: (hasExplicitMin || hasExplicitMax)\n ? buildNumericTickValues(\n hasExplicitMin ? Number(axis?.min) : domain.min,\n hasExplicitMax ? Number(axis?.max) : domain.max,\n axis?.majorUnit\n )\n : domain.ticks\n };\n}\n\nfunction resolve3dFrameOffsets(chart: XlsxChart, baseDepthX = 11, baseDepthY = 8) {\n const depthRatio = clamp((chart.view3d?.depthPercent ?? 100) / 100, 0.35, 3.2);\n const rotX = clamp(chart.view3d?.rotX ?? 20, -80, 80);\n const rotY = clamp(chart.view3d?.rotY ?? 20, -80, 80);\n const usePerspective = chart.view3d?.rAngAx === false;\n const perspectiveStrength = clamp((chart.view3d?.perspective ?? (usePerspective ? 26 : 0)) / 100, 0, 1);\n const projectedOrigin = projectCartesian3dPoint(\n 0,\n 0,\n 0,\n rotX * (Math.PI / 180),\n rotY * (Math.PI / 180),\n usePerspective,\n perspectiveStrength\n );\n const projectedDepthPoint = projectCartesian3dPoint(\n 0,\n 0,\n 1,\n rotX * (Math.PI / 180),\n rotY * (Math.PI / 180),\n usePerspective,\n perspectiveStrength\n );\n const depthDirectionX = projectedDepthPoint.x - projectedOrigin.x;\n const depthDirectionY = projectedDepthPoint.y - projectedOrigin.y;\n const horizontalBias = clamp(1.42 + Math.abs(rotY) / 48 + depthRatio * 0.06, 1.5, 1.95);\n const verticalBias = clamp(1.18 + Math.abs(rotX) / 78, 1.22, 1.5);\n const biasedDepthDirectionX = depthDirectionX * horizontalBias;\n const biasedDepthDirectionY = depthDirectionY * verticalBias;\n const depthDirectionMagnitude = Math.hypot(biasedDepthDirectionX, biasedDepthDirectionY) || 1;\n const horizontalFactor = clamp(Math.abs(rotY) / 22, 0.55, 2.2);\n const verticalFactor = clamp(Math.abs(rotX) / 18, 0.45, 1.9);\n const legacyDepthX = Math.max(6, baseDepthX * depthRatio * horizontalFactor) * (rotY < 0 ? -1 : 1);\n const legacyDepthY = -Math.max(4, baseDepthY * depthRatio * verticalFactor);\n const depthMagnitude = Math.max(10, Math.hypot(legacyDepthX, legacyDepthY) * 1.34);\n const depthX = biasedDepthDirectionX / depthDirectionMagnitude * depthMagnitude;\n const depthY = biasedDepthDirectionY / depthDirectionMagnitude * depthMagnitude;\n return {\n depthRatio,\n depthX,\n depthY,\n insetBottom: Math.max(6, Math.abs(depthY) + 5),\n insetLeft: depthX < 0 ? Math.abs(depthX) + 4 : 0,\n insetRight: depthX > 0 ? depthX + 4 : 0,\n insetTop: Math.max(4, Math.abs(depthY) + 2)\n };\n}\n\nfunction formatTickValue(value: number) {\n if (Math.abs(value) >= 1000) {\n return value.toLocaleString(undefined, { maximumFractionDigits: 0 });\n }\n return value.toLocaleString(undefined, { maximumFractionDigits: 2 });\n}\n\nfunction formatPercentTickValue(value: number) {\n return `${formatTickValue(value)}%`;\n}\n\nfunction isLikelyDateFormatCode(formatCode: string | undefined) {\n if (!formatCode) {\n return false;\n }\n const normalized = formatCode\n .toLowerCase()\n .replace(/\\[[^\\]]*]/g, \" \")\n .replace(/\"[^\"]*\"/g, \" \")\n .replace(/\\\\./g, \" \");\n return /(?:d|m|y)/.test(normalized);\n}\n\nfunction excelSerialToDate(serial: number, use1904: boolean) {\n const wholeDays = Math.trunc(serial);\n const milliseconds = Math.round((serial - wholeDays) * 86_400_000);\n const baseUtc = use1904\n ? Date.UTC(1904, 0, 1)\n : Date.UTC(1899, 11, 30);\n return new Date(baseUtc + wholeDays * 86_400_000 + milliseconds);\n}\n\nfunction formatExcelDateSerial(value: number, formatCode: string | undefined, use1904: boolean) {\n const date = excelSerialToDate(value, use1904);\n const normalized = (formatCode ?? \"\").toLowerCase();\n const options: Intl.DateTimeFormatOptions = {};\n\n if (/yyyy/.test(normalized)) {\n options.year = \"numeric\";\n } else if (/yy/.test(normalized)) {\n options.year = \"2-digit\";\n }\n\n if (/mmmm/.test(normalized)) {\n options.month = \"long\";\n } else if (/mmm/.test(normalized)) {\n options.month = \"short\";\n } else if (/(^|[^a-z])m([^a-z]|$)|(^|[^a-z])mm([^a-z]|$)/.test(normalized)) {\n options.month = \"numeric\";\n }\n\n if (/dddd/.test(normalized)) {\n options.weekday = \"long\";\n } else if (/ddd/.test(normalized)) {\n options.weekday = \"short\";\n }\n\n if (/d/.test(normalized)) {\n options.day = \"numeric\";\n }\n\n if (Object.keys(options).length === 0) {\n options.month = \"short\";\n options.day = \"numeric\";\n }\n\n return new Intl.DateTimeFormat(undefined, options).format(date);\n}\n\nfunction formatCategoryLabel(chart: XlsxChart, value: unknown, fallback = \"\") {\n const rawRecord = chart.raw && typeof chart.raw === \"object\"\n ? chart.raw as Record<string, unknown>\n : null;\n const numeric = typeof value === \"number\" && Number.isFinite(value)\n ? value\n : null;\n const formatCode = chart.categoryAxis?.numberFormat?.formatCode;\n if (numeric != null && isLikelyDateFormatCode(formatCode)) {\n return formatExcelDateSerial(numeric, formatCode, rawRecord?.date1904 === true);\n }\n\n const normalized = normalizeCategoryLabel(value);\n if (normalized.length > 0) {\n return normalized;\n }\n return fallback;\n}\n\nfunction truncateSvgText(value: string, maxWidth: number, fontSize = 10) {\n if (!value || maxWidth <= 0) {\n return \"\";\n }\n const charWidth = Math.max(4.2, fontSize * 0.56);\n const maxChars = Math.max(1, Math.floor(maxWidth / charWidth));\n if (value.length <= maxChars) {\n return value;\n }\n if (maxChars <= 1) {\n return \"…\";\n }\n return `${value.slice(0, Math.max(0, maxChars - 1)).trimEnd()}…`;\n}\n\nfunction markerRadiusPx(sizePt: number | undefined) {\n return (Number.isFinite(sizePt) && Number(sizePt) > 0 ? Number(sizePt) : 5) * 2 / 3;\n}\n\nfunction markerSymbolPath(symbol: string, radius: number) {\n const diagonal = radius / Math.SQRT2;\n switch (symbol) {\n case \"none\":\n return \"\";\n case \"diamond\":\n return `M0,${-radius}L${radius},0L0,${radius}L${-radius},0Z`;\n case \"square\":\n return `M${-radius},${-radius}H${radius}V${radius}H${-radius}Z`;\n case \"triangle\":\n case \"triangle-up\":\n return `M0,${-radius}L${radius},${radius}H${-radius}Z`;\n case \"cross\":\n case \"x\":\n return `M${-diagonal},${-diagonal}L${diagonal},${diagonal}M${-diagonal},${diagonal}L${diagonal},${-diagonal}`;\n case \"plus\":\n return `M${-radius},0H${radius}M0,${-radius}V${radius}`;\n case \"star\":\n return `M${-radius},0H${radius}M${-radius / 2},${-radius * Math.sqrt(3) / 2}L${radius / 2},${radius * Math.sqrt(3) / 2}M${-radius / 2},${radius * Math.sqrt(3) / 2}L${radius / 2},${-radius * Math.sqrt(3) / 2}`;\n case \"dash\":\n return `M${-radius},0H${radius}`;\n case \"dot\":\n return `M${-radius / 2},0H${radius / 2}`;\n default:\n return `M${radius},0A${radius},${radius} 0 1,0 ${-radius},0A${radius},${radius} 0 1,0 ${radius},0Z`;\n }\n}\n\nconst TWO_PI = Math.PI * 2;\n\nfunction normalizePieArc(startAngle: number, endAngle: number) {\n let start = startAngle;\n let end = endAngle;\n while (end < start) {\n end += TWO_PI;\n }\n return { end, start };\n}\n\nfunction resolvePieFrontSegments(startAngle: number, endAngle: number): Array<[number, number]> {\n const { start, end } = normalizePieArc(startAngle, endAngle);\n const segments: Array<[number, number]> = [];\n const minBand = Math.floor(start / TWO_PI) - 1;\n const maxBand = Math.ceil(end / TWO_PI) + 1;\n for (let band = minBand; band <= maxBand; band += 1) {\n const frontStart = Math.PI / 2 + band * TWO_PI;\n const frontEnd = Math.PI * 1.5 + band * TWO_PI;\n const segmentStart = Math.max(start, frontStart);\n const segmentEnd = Math.min(end, frontEnd);\n if (segmentEnd - segmentStart > 1e-4) {\n segments.push([segmentStart, segmentEnd]);\n }\n }\n return segments;\n}\n\nfunction pieEllipsePoint(\n centerX: number,\n centerY: number,\n radius: number,\n tilt: number,\n angle: number,\n depth = 0\n) {\n return {\n x: centerX + Math.sin(angle) * radius,\n y: centerY - Math.cos(angle) * radius * tilt + depth\n };\n}\n\nfunction toSvgNumber(value: number) {\n return Number(value.toFixed(3));\n}\n\nfunction buildPieOuterWallPath(\n centerX: number,\n centerY: number,\n radius: number,\n tilt: number,\n depth: number,\n startAngle: number,\n endAngle: number,\n fullArc = false\n) {\n const ry = radius * tilt;\n const segments = fullArc ? [[startAngle, endAngle] as [number, number]] : resolvePieFrontSegments(startAngle, endAngle);\n return segments.map(([segmentStart, segmentEnd]) => {\n const topStart = pieEllipsePoint(centerX, centerY, radius, tilt, segmentStart, 0);\n const topEnd = pieEllipsePoint(centerX, centerY, radius, tilt, segmentEnd, 0);\n const bottomStart = pieEllipsePoint(centerX, centerY, radius, tilt, segmentStart, depth);\n const bottomEnd = pieEllipsePoint(centerX, centerY, radius, tilt, segmentEnd, depth);\n const largeArc = segmentEnd - segmentStart > Math.PI ? 1 : 0;\n return [\n `M ${toSvgNumber(topStart.x)} ${toSvgNumber(topStart.y)}`,\n `A ${toSvgNumber(radius)} ${toSvgNumber(ry)} 0 ${largeArc} 1 ${toSvgNumber(topEnd.x)} ${toSvgNumber(topEnd.y)}`,\n `L ${toSvgNumber(bottomEnd.x)} ${toSvgNumber(bottomEnd.y)}`,\n `A ${toSvgNumber(radius)} ${toSvgNumber(ry)} 0 ${largeArc} 0 ${toSvgNumber(bottomStart.x)} ${toSvgNumber(bottomStart.y)}`,\n \"Z\"\n ].join(\" \");\n });\n}\n\nfunction isPieFrontFacingAngle(angle: number) {\n const normalized = ((angle % TWO_PI) + TWO_PI) % TWO_PI;\n return normalized > Math.PI / 2 && normalized < Math.PI * 1.5;\n}\n\nfunction buildPieRadialWallPath(\n centerX: number,\n centerY: number,\n radius: number,\n tilt: number,\n depth: number,\n angle: number,\n forceVisible = false\n) {\n if (!forceVisible && !isPieFrontFacingAngle(angle)) {\n return null;\n }\n const topCenter = { x: centerX, y: centerY };\n const bottomCenter = { x: centerX, y: centerY + depth };\n const topEdge = pieEllipsePoint(centerX, centerY, radius, tilt, angle, 0);\n const bottomEdge = pieEllipsePoint(centerX, centerY, radius, tilt, angle, depth);\n return [\n `M ${toSvgNumber(topCenter.x)} ${toSvgNumber(topCenter.y)}`,\n `L ${toSvgNumber(topEdge.x)} ${toSvgNumber(topEdge.y)}`,\n `L ${toSvgNumber(bottomEdge.x)} ${toSvgNumber(bottomEdge.y)}`,\n `L ${toSvgNumber(bottomCenter.x)} ${toSvgNumber(bottomCenter.y)}`,\n \"Z\"\n ].join(\" \");\n}\n\nfunction renderTitle(chart: XlsxChart, layout: ChartLayout, palette: ChartRendererPalette) {\n if (!chart.title) {\n return null;\n }\n const fontSize = 12;\n const text = truncateSvgText(chart.title, Math.max(40, layout.width - 12), fontSize);\n const baselineY = layout.titleHeight >= 30 ? 19 : 16;\n return (\n <text\n fill={chart.titleColor ?? chart.textColor ?? DEFAULT_CHART_TEXT_COLOR}\n fontFamily={buildChartFontFamily(chart.titleFontFamily ?? chart.fontFamily)}\n fontSize={fontSize}\n fontWeight={600}\n textAnchor=\"middle\"\n x={layout.width / 2}\n y={baselineY}\n >\n {text}\n </text>\n );\n}\n\nfunction renderLegend(chart: XlsxChart, layout: ChartLayout, palette: ChartRendererPalette) {\n if (!chart.legend || layout.legendItems.length === 0) {\n return null;\n }\n const textColor = resolveChartAxisTextColor(chart);\n const legendPos = layout.legendPosition;\n const items = layout.legendItems;\n const swatchSize = 8;\n const textOffset = swatchSize + 4;\n\n if (chart.chartType === \"RegionMap\") {\n const seriesIndex = Math.max(0, chart.series.findIndex((series) => series.hidden !== true));\n const series = chart.series[seriesIndex];\n if (!resolveRegionMapColorStrings(series)) {\n const vertical = legendPos === \"left\" || legendPos === \"right\";\n const x = vertical ? (legendPos === \"right\" ? layout.plot.left + layout.plot.width + 8 : 8) : layout.plot.left;\n const showSeriesName = vertical || (layout.legendBounds?.height ?? 48) >= 44;\n const y = vertical ? layout.plot.top + 26 : (layout.legendBounds?.top ?? layout.height - 48) + (showSeriesName ? 20 : 4);\n const length = vertical ? Math.min(100, Math.max(24, layout.plot.height - 42)) : Math.min(160, layout.plot.width);\n const gradientId = `map-legend-${chart.id}`;\n const stops = resolveRegionMapValueColors(series);\n const count = stops?.length ?? 3;\n return (\n <g>\n <defs>\n <linearGradient id={gradientId} x1=\"0%\" x2={vertical ? \"0%\" : \"100%\"} y1={vertical ? \"100%\" : \"0%\"} y2=\"0%\">\n {Array.from({ length: count }, (_, index) => (\n <stop key={index} offset={`${index / (count - 1) * 100}%`} stopColor={resolveRegionMapValueColor(chart, seriesIndex, index / (count - 1))} />\n ))}\n </linearGradient>\n </defs>\n {showSeriesName && <text fill={textColor} fontSize={10} x={x} y={y - 12}>{series?.name ?? \"\"}</text>}\n <rect fill={`url(#${gradientId})`} x={x} y={y} width={vertical ? 8 : length} height={vertical ? length : 8} />\n <text fill={textColor} fontSize={10} x={vertical ? x + 12 : x} y={vertical ? y + length : y + 20}>{items[0]?.label}</text>\n <text fill={textColor} fontSize={10} textAnchor={vertical ? \"start\" : \"end\"} x={vertical ? x + 12 : x + length} y={vertical ? y + 7 : y + 20}>{items[1]?.label}</text>\n </g>\n );\n }\n }\n\n if (legendPos === \"left\" || legendPos === \"right\") {\n const x = legendPos === \"right\"\n ? layout.plot.left + layout.plot.width + 8\n : 8;\n const startY = chart.chartType === \"Surface\"\n ? layout.plot.top + Math.max(6, (layout.plot.height - items.length * 18) / 2 + 9)\n : layout.plot.top + 6;\n return (\n <g>\n {items.map((item, index) => {\n const y = startY + index * 18;\n return (\n <g\n {...(index < chart.series.length ? chartElementDataProps(index) : {})}\n data-xlsx-chart-element-kind={index < chart.series.length ? \"legendEntry\" : undefined}\n key={`legend-${index}`}\n transform={`translate(${x}, ${y})`}\n >\n <rect fill={chart.chartType === \"Surface\" && chart.wireframe ? \"none\" : item.color} stroke={chart.chartType === \"Surface\" && chart.wireframe ? item.color : undefined} height={swatchSize} width={swatchSize} x={0} y={-7} />\n <text fill={textColor} fontSize={10} x={textOffset} y={0}>\n {item.label}\n </text>\n </g>\n );\n })}\n </g>\n );\n }\n\n const rowY = legendPos === \"top\" ? (layout.titleHeight + 12) : (layout.height - 8);\n const totalWidth = items.reduce((sum, item) => sum + 24 + Math.min(96, item.label.length * 5.4), 0);\n let cursorX = Math.max(8, (layout.width - totalWidth) / 2);\n return (\n <g>\n {items.map((item, index) => {\n const labelWidth = Math.min(96, item.label.length * 5.4);\n const node = (\n <g\n {...(index < chart.series.length ? chartElementDataProps(index) : {})}\n data-xlsx-chart-element-kind={index < chart.series.length ? \"legendEntry\" : undefined}\n key={`legend-${index}`}\n transform={`translate(${cursorX}, ${rowY})`}\n >\n <rect fill={chart.chartType === \"Surface\" && chart.wireframe ? \"none\" : item.color} stroke={chart.chartType === \"Surface\" && chart.wireframe ? item.color : undefined} height={swatchSize} width={swatchSize} x={0} y={-7} />\n <text fill={textColor} fontSize={10} x={textOffset} y={0}>\n {item.label}\n </text>\n </g>\n );\n cursorX += 24 + labelWidth;\n return node;\n })}\n </g>\n );\n}\n\nfunction renderCartesianAxes(\n chart: XlsxChart,\n palette: ChartRendererPalette,\n plot: PlotRect,\n isHorizontal: boolean,\n categoryLabels: string[],\n categoryPositions: number[],\n valueTicks: number[],\n mapValue: (value: number) => number,\n formatValueTick: (value: number) => string = formatTickValue\n) {\n const axisColor = chart.axisLineColor ?? chart.chartAreaBorderColor ?? palette.border;\n const labelColor = resolveChartAxisTextColor(chart);\n const zeroPosition = mapValue(0);\n const showValueAxis = chart.valueAxis?.delete !== true;\n const showCategoryAxis = chart.categoryAxis?.delete !== true;\n const showValueLabels = showValueAxis && chart.valueAxis?.labelPosition !== \"none\";\n const showCategoryLabels = showCategoryAxis && chart.categoryAxis?.labelPosition !== \"none\";\n\n return (\n <g>\n {showValueAxis ? valueTicks.map((tick) => {\n const valuePosition = mapValue(tick);\n if (isHorizontal) {\n return (\n <g key={`grid-v-${tick}`}>\n <line\n stroke={lightenColor(axisColor, 0.7)}\n strokeWidth={1}\n x1={valuePosition}\n x2={valuePosition}\n y1={plot.top}\n y2={plot.top + plot.height}\n />\n {showValueLabels ? <text\n fill={labelColor}\n fontSize={10}\n textAnchor=\"middle\"\n x={valuePosition}\n y={plot.top + plot.height + 14}\n >\n {formatValueTick(tick)}\n </text> : null}\n </g>\n );\n }\n return (\n <g key={`grid-h-${tick}`}>\n <line\n stroke={lightenColor(axisColor, 0.7)}\n strokeWidth={1}\n x1={plot.left}\n x2={plot.left + plot.width}\n y1={valuePosition}\n y2={valuePosition}\n />\n {showValueLabels ? <text\n fill={labelColor}\n fontSize={10}\n textAnchor=\"end\"\n x={plot.left - 6}\n y={valuePosition + 3}\n >\n {formatValueTick(tick)}\n </text> : null}\n </g>\n );\n }) : null}\n {showCategoryLabels ? categoryPositions.map((position, index) => {\n const label = categoryLabels[index] ?? \"\";\n if (isHorizontal) {\n return (\n <text\n key={`cat-y-${index}`}\n fill={labelColor}\n fontSize={10}\n textAnchor=\"end\"\n x={plot.left - 6}\n y={position + 3}\n >\n {label}\n </text>\n );\n }\n return (\n <text\n key={`cat-x-${index}`}\n fill={labelColor}\n fontSize={10}\n textAnchor=\"middle\"\n x={position}\n y={plot.top + plot.height + 14}\n >\n {label}\n </text>\n );\n }) : null}\n {isHorizontal ? (\n <>\n {showValueAxis ? <line\n stroke={axisColor}\n strokeWidth={1.2}\n x1={plot.left}\n x2={plot.left + plot.width}\n y1={plot.top + plot.height}\n y2={plot.top + plot.height}\n /> : null}\n {showCategoryAxis ? <line\n stroke={axisColor}\n strokeWidth={1.2}\n x1={zeroPosition}\n x2={zeroPosition}\n y1={plot.top}\n y2={plot.top + plot.height}\n /> : null}\n </>\n ) : (\n <>\n {showValueAxis ? <line\n stroke={axisColor}\n strokeWidth={1.2}\n x1={plot.left}\n x2={plot.left}\n y1={plot.top}\n y2={plot.top + plot.height}\n /> : null}\n {showCategoryAxis ? <line\n stroke={axisColor}\n strokeWidth={1.2}\n x1={plot.left}\n x2={plot.left + plot.width}\n y1={zeroPosition}\n y2={zeroPosition}\n /> : null}\n </>\n )}\n </g>\n );\n}\n\nfunction scaleProjectedVector(vector: { x: number; y: number }, scale: number) {\n return {\n x: vector.x * scale,\n y: vector.y * scale\n };\n}\n\nfunction sampleProjectedEllipseArc(\n center: { x: number; y: number },\n axisA: { x: number; y: number },\n axisB: { x: number; y: number },\n startAngle: number,\n endAngle: number\n) {\n const steps = Math.max(12, Math.ceil(Math.abs(endAngle - startAngle) / (Math.PI / 14)));\n const points: Array<{ x: number; y: number }> = [];\n for (let step = 0; step <= steps; step += 1) {\n const ratio = step / steps;\n const angle = startAngle + ((endAngle - startAngle) * ratio);\n points.push({\n x: center.x + (axisA.x * Math.cos(angle)) + (axisB.x * Math.sin(angle)),\n y: center.y + (axisA.y * Math.cos(angle)) + (axisB.y * Math.sin(angle))\n });\n }\n return points;\n}\n\nfunction buildRibbonSvgPath(startArc: Array<{ x: number; y: number }>, endArc: Array<{ x: number; y: number }>) {\n if (startArc.length === 0 || endArc.length === 0) {\n return \"\";\n }\n return buildLinearSvgPath([...startArc, ...endArc.slice().reverse()], true);\n}\n\nfunction renderRadialFrustum(\n bar: BarRect,\n normalizedShape: \"cone\" | \"cylinder\",\n frontFill: string,\n sideFill: string,\n topFill: string\n) {\n const depthX = bar.depthX ?? (bar.isHorizontal ? 10 : 9);\n const depthY = bar.depthY ?? -7;\n const frontX = bar.left + (bar.depthOffsetX ?? 0);\n const frontY = bar.top + (bar.depthOffsetY ?? 0);\n const frontW = bar.width;\n const frontH = bar.height;\n const centerX = frontX + frontW / 2;\n const centerY = frontY + frontH / 2;\n const showStartCap = bar.capStart !== false;\n const showEndCap = bar.capEnd !== false;\n const startScale = normalizedShape === \"cone\" ? clamp(bar.bottomScale ?? 1, 0, 1) : 1;\n const endScale = normalizedShape === \"cone\" ? clamp(bar.topScale ?? 1, 0, 1) : 1;\n const radialDepthScale = normalizedShape === \"cylinder\"\n ? (bar.isHorizontal ? 0.52 : 0.48)\n : (bar.isHorizontal ? 0.7 : 0.58);\n const depthAxis = scaleProjectedVector({ x: depthX / 2, y: depthY / 2 }, radialDepthScale);\n const secondaryStrokeWidth = Math.max(0.6, bar.strokeWidth * 0.65);\n\n if (bar.isHorizontal) {\n const startCenter = { x: frontX + depthAxis.x, y: centerY + depthAxis.y };\n const endCenter = { x: frontX + frontW + depthAxis.x, y: centerY + depthAxis.y };\n const startAxisA = { x: 0, y: (frontH * startScale) / 2 };\n const endAxisA = { x: 0, y: (frontH * endScale) / 2 };\n const startAxisB = scaleProjectedVector(depthAxis, startScale);\n const endAxisB = scaleProjectedVector(depthAxis, endScale);\n const backStartArc = sampleProjectedEllipseArc(startCenter, startAxisA, startAxisB, 0, Math.PI);\n const backEndArc = sampleProjectedEllipseArc(endCenter, endAxisA, endAxisB, 0, Math.PI);\n const frontStartArc = sampleProjectedEllipseArc(startCenter, startAxisA, startAxisB, Math.PI, Math.PI * 2);\n const frontEndArc = sampleProjectedEllipseArc(endCenter, endAxisA, endAxisB, Math.PI, Math.PI * 2);\n const backWallPath = buildRibbonSvgPath(backEndArc, backStartArc);\n const frontWallPath = buildRibbonSvgPath(frontEndArc, frontStartArc);\n const endCapPath = endScale > 0.018\n ? buildLinearSvgPath(sampleProjectedEllipseArc(endCenter, endAxisA, endAxisB, 0, Math.PI * 2), true)\n : \"\";\n const startCapPath = startScale > 0.028\n ? buildLinearSvgPath(sampleProjectedEllipseArc(startCenter, startAxisA, startAxisB, 0, Math.PI * 2), true)\n : \"\";\n return (\n <g key={`${bar.key}-3d-horizontal-${normalizedShape}`}>\n {backWallPath ? <path d={backWallPath} fill={sideFill} stroke={bar.stroke} strokeWidth={secondaryStrokeWidth} /> : null}\n {showEndCap && endCapPath ? <path d={endCapPath} fill={topFill} stroke={bar.stroke} strokeWidth={secondaryStrokeWidth} /> : null}\n {frontWallPath ? <path d={frontWallPath} fill={frontFill} stroke={bar.stroke} strokeWidth={bar.strokeWidth} /> : null}\n {showStartCap && startCapPath ? <path d={startCapPath} fill={frontFill} stroke={bar.stroke} strokeWidth={secondaryStrokeWidth} /> : null}\n </g>\n );\n }\n\n const startCenter = { x: centerX + depthAxis.x, y: frontY + frontH + depthAxis.y };\n const endCenter = { x: centerX + depthAxis.x, y: frontY + depthAxis.y };\n const startAxisA = { x: (frontW * startScale) / 2, y: 0 };\n const endAxisA = { x: (frontW * endScale) / 2, y: 0 };\n const startAxisB = scaleProjectedVector(depthAxis, startScale);\n const endAxisB = scaleProjectedVector(depthAxis, endScale);\n const backStartArc = sampleProjectedEllipseArc(startCenter, startAxisA, startAxisB, 0, Math.PI);\n const backEndArc = sampleProjectedEllipseArc(endCenter, endAxisA, endAxisB, 0, Math.PI);\n const frontStartArc = sampleProjectedEllipseArc(startCenter, startAxisA, startAxisB, Math.PI, Math.PI * 2);\n const frontEndArc = sampleProjectedEllipseArc(endCenter, endAxisA, endAxisB, Math.PI, Math.PI * 2);\n const backWallPath = buildRibbonSvgPath(backEndArc, backStartArc);\n const frontWallPath = buildRibbonSvgPath(frontEndArc, frontStartArc);\n const endCapPath = endScale > 0.018\n ? buildLinearSvgPath(sampleProjectedEllipseArc(endCenter, endAxisA, endAxisB, 0, Math.PI * 2), true)\n : \"\";\n return (\n <g key={`${bar.key}-3d-${normalizedShape}`}>\n {backWallPath ? <path d={backWallPath} fill={sideFill} stroke={bar.stroke} strokeWidth={secondaryStrokeWidth} /> : null}\n {showEndCap && endCapPath ? <path d={endCapPath} fill={topFill} stroke={bar.stroke} strokeWidth={secondaryStrokeWidth} /> : null}\n {frontWallPath ? <path d={frontWallPath} fill={frontFill} stroke={bar.stroke} strokeWidth={bar.strokeWidth} /> : null}\n </g>\n );\n}\n\nfunction renderExtrudedRect(bar: BarRect) {\n const normalizedShape = (() => {\n switch (bar.shape3d) {\n case \"cone\":\n case \"coneToMax\":\n return \"cone\";\n case \"cylinder\":\n return \"cylinder\";\n case \"pyramid\":\n case \"pyramidToMax\":\n return \"pyramid\";\n default:\n return \"box\";\n }\n })();\n const depthX = bar.depthX ?? (bar.isHorizontal ? 10 : 9);\n const depthY = bar.depthY ?? -7;\n const frontX = bar.left + (bar.depthOffsetX ?? 0);\n const frontY = bar.top + (bar.depthOffsetY ?? 0);\n const frontW = bar.width;\n const frontH = bar.height;\n const frontX2 = frontX + frontW;\n const frontY2 = frontY + frontH;\n\n const sideAnchorX = frontX2;\n const sideDepthX = depthX;\n const centerX = frontX + frontW / 2;\n const bottomScale = clamp(bar.bottomScale ?? 1, 0.04, 1);\n const topScale = clamp(bar.topScale ?? 1, 0.04, 1);\n const bottomHalfWidth = (frontW * bottomScale) / 2;\n const topHalfWidth = (frontW * topScale) / 2;\n const bottomLeft = centerX - bottomHalfWidth;\n const bottomRight = centerX + bottomHalfWidth;\n const topLeft = centerX - topHalfWidth;\n const topRight = centerX + topHalfWidth;\n const showStartCap = bar.capStart !== false;\n const showEndCap = bar.capEnd !== false;\n\n const topFace = `${frontX},${frontY} ${frontX2},${frontY} ${frontX2 + sideDepthX},${frontY + depthY} ${frontX + sideDepthX},${frontY + depthY}`;\n const sideFace = `${sideAnchorX},${frontY} ${sideAnchorX},${frontY2} ${sideAnchorX + sideDepthX},${frontY2 + depthY} ${sideAnchorX + sideDepthX},${frontY + depthY}`;\n const frontFill = bar.gradientId ? `url(#${bar.gradientId})` : bar.color;\n const sideFill = bar.invertedNegative ? bar.color : darkenColor(bar.color, 0.22);\n const topFill = bar.invertedNegative ? lightenColor(bar.color, 0.04) : lightenColor(bar.color, 0.24);\n\n if (normalizedShape === \"cylinder\" || normalizedShape === \"cone\") {\n return renderRadialFrustum(bar, normalizedShape, frontFill, sideFill, topFill);\n }\n\n if (normalizedShape === \"box\") {\n return (\n <g key={`${bar.key}-3d`}>\n <polygon fill={sideFill} points={sideFace} stroke={bar.stroke} strokeWidth={Math.max(0.6, bar.strokeWidth * 0.65)} />\n <polygon fill={topFill} points={topFace} stroke={bar.stroke} strokeWidth={Math.max(0.6, bar.strokeWidth * 0.65)} />\n <rect fill={frontFill} height={frontH} stroke={bar.stroke} strokeWidth={bar.strokeWidth} width={frontW} x={frontX} y={frontY} />\n </g>\n );\n }\n\n if (bar.isHorizontal) {\n const centerY = frontY + frontH / 2;\n const startHalfHeight = (frontH * clamp(bar.bottomScale ?? 1, 0.04, 1)) / 2;\n const endHalfHeight = (frontH * clamp(bar.topScale ?? 1, 0.04, 1)) / 2;\n const startTop = centerY - startHalfHeight;\n const startBottom = centerY + startHalfHeight;\n const endTop = centerY - endHalfHeight;\n const endBottom = centerY + endHalfHeight;\n const topFacePoints = `${frontX},${startTop} ${frontX2},${endTop} ${frontX2 + sideDepthX},${endTop + depthY} ${frontX + sideDepthX},${startTop + depthY}`;\n const farSidePoints = `${frontX2},${endTop} ${frontX2},${endBottom} ${frontX2 + sideDepthX},${endBottom + depthY} ${frontX2 + sideDepthX},${endTop + depthY}`;\n\n const taperedFarFace = `${frontX2},${endTop} ${frontX2 + sideDepthX},${endTop + depthY} ${frontX2 + sideDepthX},${endBottom + depthY} ${frontX2},${endBottom}`;\n const frontPolygon = `${frontX},${startTop} ${frontX2},${endTop} ${frontX2},${endBottom} ${frontX},${startBottom}`;\n\n return (\n <g key={`${bar.key}-3d-horizontal-${normalizedShape}`}>\n <polygon fill={sideFill} points={taperedFarFace} stroke={bar.stroke} strokeWidth={Math.max(0.6, bar.strokeWidth * 0.65)} />\n <polygon fill={topFill} points={topFacePoints} stroke={bar.stroke} strokeWidth={Math.max(0.6, bar.strokeWidth * 0.65)} />\n <polygon fill={frontFill} points={frontPolygon} stroke={bar.stroke} strokeWidth={bar.strokeWidth} />\n </g>\n );\n }\n\n const taperedTopFace = `${topLeft},${frontY} ${topRight},${frontY} ${topRight + sideDepthX},${frontY + depthY} ${topLeft + sideDepthX},${frontY + depthY}`;\n const taperedSideFace = `${topRight},${frontY} ${bottomRight},${frontY2} ${bottomRight + sideDepthX},${frontY2 + depthY} ${topRight + sideDepthX},${frontY + depthY}`;\n const pyramidFrontFace = `${topLeft},${frontY} ${topRight},${frontY} ${bottomRight},${frontY2} ${bottomLeft},${frontY2}`;\n\n return (\n <g key={`${bar.key}-3d-${normalizedShape}`}>\n <polygon fill={sideFill} points={taperedSideFace} stroke={bar.stroke} strokeWidth={Math.max(0.6, bar.strokeWidth * 0.65)} />\n {showEndCap ? (\n <polygon fill={topFill} points={taperedTopFace} stroke={bar.stroke} strokeWidth={Math.max(0.6, bar.strokeWidth * 0.65)} />\n ) : null}\n <polygon fill={frontFill} points={pyramidFrontFace} stroke={bar.stroke} strokeWidth={bar.strokeWidth} />\n </g>\n );\n}\n\nfunction buildLinearSvgPath(points: Array<{ x: number; y: number }>, close = false) {\n if (points.length === 0) {\n return \"\";\n }\n const commands = points.map((point, index) => (\n `${index === 0 ? \"M\" : \"L\"} ${toSvgNumber(point.x)} ${toSvgNumber(point.y)}`\n ));\n if (close) {\n commands.push(\"Z\");\n }\n return commands.join(\" \");\n}\n\nfunction projectCartesian3dPoint(\n x: number,\n y: number,\n z: number,\n rotXRad: number,\n rotYRad: number,\n usePerspective: boolean,\n perspectiveStrength: number\n) {\n const cosX = Math.cos(rotXRad);\n const sinX = Math.sin(rotXRad);\n const cosY = Math.cos(rotYRad);\n const sinY = Math.sin(rotYRad);\n\n const x1 = x * cosY + z * sinY;\n const z1 = -x * sinY + z * cosY;\n const y1 = y * cosX - z1 * sinX;\n const z2 = y * sinX + z1 * cosX;\n const perspective = usePerspective\n ? 1 / Math.max(0.22, 1 + z2 * (0.26 + perspectiveStrength * 0.54))\n : 1;\n\n return {\n depth: z2,\n x: x1 * perspective,\n y: y1 * perspective\n };\n}\n\nfunction renderLineOrAreaChart3d(\n chart: XlsxChart,\n palette: ChartRendererPalette,\n layout: ChartLayout,\n categories: string[],\n stackedPointsBySeries: Array<Array<{ defined: boolean; y: number | null; y0: number | null; y1: number | null }>>,\n minValue: number,\n maxValue: number,\n isAreaChart: boolean,\n isStackedSeries: boolean,\n selectedChartElement?: XlsxChartElementSelection | null\n) {\n const plot = layout.plot;\n const valueDomain = resolveAxisDomainWithChartOverrides(\n chart.valueAxis,\n minValue,\n maxValue,\n isAreaChart || chart.valueAxis?.crosses === \"autoZero\"\n );\n minValue = valueDomain.min;\n maxValue = valueDomain.max;\n const valueSpan = Math.max(1e-6, maxValue - minValue);\n const seriesCount = Math.max(1, chart.series.length);\n const categoryCount = Math.max(1, categories.length);\n const depthScale = clamp((chart.view3d?.depthPercent ?? 100) / 100, 0.5, 4);\n const halfDepth = (seriesCount <= 1 ? 0.82 : 1.02) * depthScale;\n const frontZ = halfDepth;\n const backZ = -halfDepth;\n const baseValue = isAreaChart ? Math.max(minValue, Math.min(maxValue, 0)) : minValue;\n const rotXRad = clamp(chart.view3d?.rotX ?? 18, -80, 80) * (Math.PI / 180);\n const rotYRad = clamp(chart.view3d?.rotY ?? 24, -80, 80) * (Math.PI / 180);\n const usePerspective = chart.view3d?.rAngAx === false;\n const perspectiveStrength = clamp((chart.view3d?.perspective ?? (usePerspective ? 26 : 0)) / 100, 0, 1);\n\n const normalizeX = (categoryIndex: number) => (\n categoryCount <= 1 ? 0 : ((categoryIndex / (categoryCount - 1)) - 0.5) * 2\n );\n const normalizeY = (value: number) => (\n -((((value - minValue) / valueSpan) - 0.5) * 2)\n );\n const stackedAreaDepthSpan = isAreaChart && isStackedSeries\n ? Math.max(0.18, (frontZ - backZ) * 0.56)\n : 0;\n const stackedAreaBackZ = frontZ - stackedAreaDepthSpan;\n const normalizeZ = (seriesIndex: number) => (\n seriesCount <= 1 || (isAreaChart && isStackedSeries)\n ? frontZ * 0.94\n : (((seriesIndex / (seriesCount - 1)) - 0.5) * (frontZ - backZ))\n );\n const projectSeriesPoint = (x: number, value: number, z: number) => projectCartesian3dPoint(\n x,\n normalizeY(value),\n z,\n rotXRad,\n rotYRad,\n usePerspective,\n perspectiveStrength\n );\n\n const cubeCorners = [\n { x: -1, y: -1, z: backZ },\n { x: 1, y: -1, z: backZ },\n { x: 1, y: 1, z: backZ },\n { x: -1, y: 1, z: backZ },\n { x: -1, y: -1, z: frontZ },\n { x: 1, y: -1, z: frontZ },\n { x: 1, y: 1, z: frontZ },\n { x: -1, y: 1, z: frontZ }\n ].map((corner) => projectCartesian3dPoint(\n corner.x,\n corner.y,\n corner.z,\n rotXRad,\n rotYRad,\n usePerspective,\n perspectiveStrength\n ));\n\n const projectedSeries = stackedPointsBySeries.map((seriesPoints, seriesIndex) => {\n const z = normalizeZ(seriesIndex);\n return seriesPoints.map((point, categoryIndex) => {\n const x = normalizeX(categoryIndex);\n const topValue = isStackedSeries ? (point.y1 ?? point.y ?? baseValue) : (point.y ?? baseValue);\n const bottomValue = isAreaChart\n ? (isStackedSeries ? (point.y0 ?? baseValue) : baseValue)\n : baseValue;\n const top = projectSeriesPoint(x, topValue, z);\n const bottom = projectSeriesPoint(x, bottomValue, z);\n const topBack = isAreaChart && isStackedSeries\n ? projectSeriesPoint(x, topValue, stackedAreaBackZ)\n : null;\n const bottomBack = isAreaChart && isStackedSeries\n ? projectSeriesPoint(x, bottomValue, stackedAreaBackZ)\n : null;\n return {\n bottom,\n bottomBack,\n categoryIndex,\n defined: point.defined,\n depth: top.depth,\n depthBack: topBack?.depth ?? top.depth,\n top,\n topBack\n };\n });\n });\n\n const bounds = [\n ...cubeCorners,\n ...projectedSeries.flatMap((series) => series.flatMap((point) => point.defined\n ? [point.top, point.bottom, ...(point.topBack ? [point.topBack] : []), ...(point.bottomBack ? [point.bottomBack] : [])]\n : []))\n ];\n const minX = Math.min(...bounds.map((point) => point.x));\n const maxX = Math.max(...bounds.map((point) => point.x));\n const minY = Math.min(...bounds.map((point) => point.y));\n const maxY = Math.max(...bounds.map((point) => point.y));\n const scale = Math.min(\n plot.width / Math.max(0.4, maxX - minX),\n plot.height / Math.max(0.4, maxY - minY)\n ) * 0.82;\n const centerRawX = (minX + maxX) / 2;\n const centerRawY = (minY + maxY) / 2;\n const centerX = plot.left + plot.width / 2;\n const centerY = plot.top + plot.height / 2;\n const toScreenPoint = (point: { depth: number; x: number; y: number }) => ({\n depth: point.depth,\n x: centerX + (point.x - centerRawX) * scale,\n y: centerY + (point.y - centerRawY) * scale\n });\n\n const screenCorners = cubeCorners.map(toScreenPoint);\n const seriesGeometry = projectedSeries.map((series, seriesIndex) => ({\n averageDepth: series.reduce((sum, point) => sum + ((point.depth + point.depthBack) / 2), 0) / Math.max(1, series.length),\n points: series.map((point) => ({\n bottom: toScreenPoint(point.bottom),\n bottomBack: point.bottomBack ? toScreenPoint(point.bottomBack) : null,\n categoryIndex: point.categoryIndex,\n defined: point.defined,\n top: toScreenPoint(point.top),\n topBack: point.topBack ? toScreenPoint(point.topBack) : null\n })),\n seriesIndex\n })).sort((left, right) => left.averageDepth - right.averageDepth);\n\n const edgeColor = chart.axisLineColor ?? chart.chartAreaBorderColor ?? palette.border;\n const gridColor = lightenColor(edgeColor, 0.56);\n const labelColor = resolveChartAxisTextColor(chart);\n const boxEdges: Array<[number, number, boolean]> = [\n [0, 1, false], [1, 2, false], [2, 3, false], [3, 0, false],\n [4, 5, true], [5, 6, true], [6, 7, true], [7, 4, true],\n [0, 4, false], [1, 5, true], [2, 6, true], [3, 7, false]\n ];\n const yTicks = valueDomain.ticks;\n const xLabelPoints = categories.map((category, categoryIndex) => ({\n label: category,\n point: toScreenPoint(projectCartesian3dPoint(\n normalizeX(categoryIndex),\n -1.06,\n frontZ,\n rotXRad,\n rotYRad,\n usePerspective,\n perspectiveStrength\n ))\n }));\n const yLabelPoints = yTicks.map((tick) => ({\n point: toScreenPoint(projectCartesian3dPoint(\n -1.04,\n normalizeY(tick),\n frontZ,\n rotXRad,\n rotYRad,\n usePerspective,\n perspectiveStrength\n )),\n tick\n }));\n\n return (\n <g>\n {yTicks.map((tick) => {\n const yNorm = normalizeY(tick);\n const leftBack = toScreenPoint(projectCartesian3dPoint(-1, yNorm, backZ, rotXRad, rotYRad, usePerspective, perspectiveStrength));\n const rightBack = toScreenPoint(projectCartesian3dPoint(1, yNorm, backZ, rotXRad, rotYRad, usePerspective, perspectiveStrength));\n const leftFront = toScreenPoint(projectCartesian3dPoint(-1, yNorm, frontZ, rotXRad, rotYRad, usePerspective, perspectiveStrength));\n return (\n <g key={`line3d-grid-${tick}`}>\n <line stroke={gridColor} strokeWidth={1} x1={leftBack.x} x2={rightBack.x} y1={leftBack.y} y2={rightBack.y} />\n <line stroke={gridColor} strokeWidth={0.9} x1={leftBack.x} x2={leftFront.x} y1={leftBack.y} y2={leftFront.y} />\n </g>\n );\n })}\n {boxEdges.map(([startIndex, endIndex, emphasized], index) => {\n const start = screenCorners[startIndex];\n const end = screenCorners[endIndex];\n return (\n <line\n key={`line3d-box-${index}`}\n stroke={emphasized ? edgeColor : lightenColor(edgeColor, 0.34)}\n strokeWidth={emphasized ? 1.35 : 1}\n x1={start.x}\n x2={end.x}\n y1={start.y}\n y2={end.y}\n />\n );\n })}\n {seriesGeometry.map(({ points, seriesIndex }) => {\n const definedPoints = points.filter((point) => point.defined);\n if (definedPoints.length === 0) {\n return null;\n }\n const linePoints = definedPoints.map((point) => point.top);\n const areaPoints = isAreaChart\n ? [\n ...definedPoints.map((point) => point.top),\n ...definedPoints.slice().reverse().map((point) => point.bottom)\n ]\n : [];\n const areaBackPoints = isAreaChart && isStackedSeries\n ? [\n ...definedPoints.map((point) => point.topBack ?? point.top),\n ...definedPoints.slice().reverse().map((point) => point.bottomBack ?? point.bottom)\n ]\n : [];\n const strokeColor = chartSeriesStrokeColor(chart, seriesIndex);\n const fillColor = chartSeriesColor(chart, seriesIndex);\n const markerSymbol = normalizeChartMarkerSymbol(chart.series[seriesIndex]?.markerSymbol);\n const markerPath = markerSymbolPath(markerSymbol, markerRadiusPx(chart.series[seriesIndex]?.markerSize));\n const slabFaces = isAreaChart && isStackedSeries\n ? definedPoints.slice(1).map((point, pointIndex) => {\n const previous = definedPoints[pointIndex];\n if (!previous?.topBack || !point.topBack || !previous.bottomBack || !point.bottomBack) {\n return null;\n }\n const topFace = buildLinearSvgPath([previous.top, point.top, point.topBack, previous.topBack], true);\n const bottomFace = buildLinearSvgPath([previous.bottom, point.bottom, point.bottomBack, previous.bottomBack], true);\n return (\n <React.Fragment key={`line3d-area-face-${seriesIndex}-${pointIndex}`}>\n <path\n {...chartElementDataProps(seriesIndex)}\n d={topFace}\n fill={lightenColor(fillColor, 0.08)}\n fillOpacity={0.8}\n stroke={darkenColor(fillColor, 0.16)}\n strokeWidth={0.8}\n />\n <path\n {...chartElementDataProps(seriesIndex)}\n d={bottomFace}\n fill={darkenColor(fillColor, 0.2)}\n fillOpacity={0.34}\n stroke={darkenColor(fillColor, 0.24)}\n strokeWidth={0.6}\n />\n </React.Fragment>\n );\n })\n : [];\n const firstDefinedPoint = definedPoints[0] ?? null;\n const lastDefinedPoint = definedPoints[definedPoints.length - 1] ?? null;\n const startCap = isAreaChart && isStackedSeries && firstDefinedPoint?.topBack && firstDefinedPoint?.bottomBack\n ? buildLinearSvgPath([\n firstDefinedPoint.top,\n firstDefinedPoint.bottom,\n firstDefinedPoint.bottomBack,\n firstDefinedPoint.topBack\n ], true)\n : \"\";\n const endCap = isAreaChart && isStackedSeries && lastDefinedPoint?.topBack && lastDefinedPoint?.bottomBack\n ? buildLinearSvgPath([\n lastDefinedPoint.top,\n lastDefinedPoint.bottom,\n lastDefinedPoint.bottomBack,\n lastDefinedPoint.topBack\n ], true)\n : \"\";\n\n return (\n <g key={`line3d-series-${seriesIndex}`}>\n {isAreaChart && isStackedSeries && areaBackPoints.length >= 3 ? (\n <path\n {...chartElementDataProps(seriesIndex)}\n d={buildLinearSvgPath(areaBackPoints, true)}\n fill={darkenColor(fillColor, 0.18)}\n fillOpacity={0.44}\n stroke={darkenColor(fillColor, 0.26)}\n strokeWidth={0.8}\n />\n ) : null}\n {slabFaces}\n {startCap ? (\n <path\n {...chartElementDataProps(seriesIndex)}\n d={startCap}\n fill={darkenColor(fillColor, 0.24)}\n fillOpacity={0.54}\n stroke={darkenColor(fillColor, 0.3)}\n strokeWidth={0.7}\n />\n ) : null}\n {endCap ? (\n <path\n {...chartElementDataProps(seriesIndex)}\n d={endCap}\n fill={darkenColor(fillColor, 0.14)}\n fillOpacity={0.6}\n stroke={darkenColor(fillColor, 0.24)}\n strokeWidth={0.7}\n />\n ) : null}\n {isAreaChart && areaPoints.length >= 3 ? (\n <path\n {...chartElementDataProps(seriesIndex)}\n d={buildLinearSvgPath(areaPoints, true)}\n fill={fillColor}\n fillOpacity={0.74}\n stroke={darkenColor(fillColor, 0.12)}\n strokeWidth={0.9}\n />\n ) : null}\n {!isAreaChart\n ? definedPoints.map((point, pointIndex) => (\n <line\n key={`line3d-drop-${seriesIndex}-${pointIndex}`}\n stroke={lightenColor(strokeColor, 0.44)}\n strokeDasharray=\"2 2\"\n strokeWidth={0.9}\n x1={point.top.x}\n x2={point.bottom.x}\n y1={point.top.y}\n y2={point.bottom.y}\n />\n ))\n : null}\n <path\n {...chartElementDataProps(seriesIndex)}\n d={buildLinearSvgPath(linePoints)}\n fill=\"none\"\n stroke={strokeColor}\n strokeLinejoin=\"round\"\n strokeWidth={Math.max(1.8, chart.series[seriesIndex]?.lineWidthPx ?? 2)}\n />\n {markerPath.length > 0\n ? definedPoints.map((point, pointIndex) => (\n <g\n key={`line3d-marker-${seriesIndex}-${pointIndex}`}\n transform={`translate(${toSvgNumber(point.top.x)}, ${toSvgNumber(point.top.y)})`}\n >\n <path\n {...chartElementDataProps(seriesIndex, point.categoryIndex)}\n d={markerPath}\n fill={chart.series[seriesIndex]?.markerColor ?? fillColor}\n stroke={chart.series[seriesIndex]?.markerLineColor ?? chart.chartAreaFillColor ?? palette.surface}\n strokeWidth={1}\n />\n </g>\n ))\n : null}\n {definedPoints.map((point) => (\n <circle\n {...chartElementDataProps(seriesIndex, point.categoryIndex)}\n cx={point.top.x}\n cy={point.top.y}\n fill=\"transparent\"\n key={`line3d-hit-${seriesIndex}-${point.categoryIndex}`}\n r={7}\n stroke=\"none\"\n />\n ))}\n {definedPoints.map((point) => (\n isSelectedChartPointOrSeries(selectedChartElement, chart.id, seriesIndex, point.categoryIndex)\n ? renderSelectionPointHandles(\n `line3d-selection-${seriesIndex}-${point.categoryIndex}`,\n [{ x: point.top.x, y: point.top.y }]\n )\n : null\n ))}\n </g>\n );\n })}\n {yLabelPoints.map(({ point, tick }) => (\n <text\n key={`line3d-y-label-${tick}`}\n fill={labelColor}\n fontSize={10}\n textAnchor=\"end\"\n x={point.x - 6}\n y={point.y + 3}\n >\n {formatTickValue(tick)}\n </text>\n ))}\n {xLabelPoints.map(({ label, point }, index) => (\n <text\n key={`line3d-x-label-${index}`}\n fill={labelColor}\n fontSize={10}\n textAnchor=\"middle\"\n x={point.x}\n y={point.y + 14}\n >\n {label}\n </text>\n ))}\n </g>\n );\n}\n\nfunction renderBarChart(chart: XlsxChart, palette: ChartRendererPalette, layout: ChartLayout, chartType: string, selectedChartElement?: XlsxChartElementSelection | null) {\n if (chart.series.length === 0) {\n return null;\n }\n const sourceCategories = getCategoryLabels(chart);\n if (sourceCategories.length === 0) {\n return null;\n }\n const isPercentStacked = chartType === \"ColumnPercentStacked\" || chartType === \"BarPercentStacked\";\n const isHorizontal = chartType === \"BarClustered\" || chartType === \"BarStacked\" || chartType === \"BarPercentStacked\";\n const isHistogramLike = isHistogramLikeChart(chart) && chartType === \"ColumnClustered\";\n const shouldReverseCategories = isHorizontal && chart.categoryAxis?.orientation !== \"maxMin\";\n const categories = shouldReverseCategories ? sourceCategories.slice().reverse() : sourceCategories;\n const isStacked = chartType === \"ColumnStacked\" || chartType === \"BarStacked\" || isPercentStacked;\n const negativeFillMode: \"chartArea\" | \"none\" | \"series\" = isPercentStacked\n ? \"chartArea\"\n : chartType === \"ColumnClustered\"\n ? \"none\"\n : \"series\";\n const categoryCount = categories.length;\n const seriesCount = chart.series.length;\n const normalized3dShape = (() => {\n switch (chart.shape3d) {\n case \"cone\":\n case \"coneToMax\":\n return \"cone\";\n case \"cylinder\":\n return \"cylinder\";\n case \"pyramid\":\n case \"pyramidToMax\":\n return \"pyramid\";\n default:\n return \"box\";\n }\n })();\n const frameOffsets = chart.is3d ? resolve3dFrameOffsets(chart, isHorizontal ? 9 : 11, isHorizontal ? 7 : 8) : null;\n const plot = chart.is3d && frameOffsets\n ? {\n ...layout.plot,\n height: Math.max(20, layout.plot.height - frameOffsets.insetBottom - 2),\n left: layout.plot.left + frameOffsets.insetLeft,\n top: layout.plot.top + frameOffsets.insetTop,\n width: Math.max(20, layout.plot.width - frameOffsets.insetLeft - frameOffsets.insetRight - 2)\n }\n : layout.plot;\n\n const matrix = chart.series.map((series) => {\n const values = Array.from(\n { length: categoryCount },\n (_, categoryIndex) => safeNumber(series.values[categoryIndex]) ?? 0\n );\n return shouldReverseCategories ? values.reverse() : values;\n });\n const rawMatrix = matrix.map((row) => row.slice());\n\n if (isPercentStacked) {\n for (let categoryIndex = 0; categoryIndex < categoryCount; categoryIndex += 1) {\n const total = matrix.reduce((sum, row) => sum + Math.max(0, row[categoryIndex] ?? 0), 0);\n for (let seriesIndex = 0; seriesIndex < seriesCount; seriesIndex += 1) {\n matrix[seriesIndex][categoryIndex] = total > 0 ? ((matrix[seriesIndex][categoryIndex] ?? 0) / total) * 100 : 0;\n }\n }\n }\n\n const positiveTotals = Array.from({ length: categoryCount }, (_, categoryIndex) => (\n matrix.reduce((sum, row) => sum + Math.max(0, row[categoryIndex] ?? 0), 0)\n ));\n const negativeTotals = Array.from({ length: categoryCount }, (_, categoryIndex) => (\n Math.abs(matrix.reduce((sum, row) => sum + Math.min(0, row[categoryIndex] ?? 0), 0))\n ));\n\n let minValue = Number.POSITIVE_INFINITY;\n let maxValue = Number.NEGATIVE_INFINITY;\n if (isStacked) {\n for (let categoryIndex = 0; categoryIndex < categoryCount; categoryIndex += 1) {\n let positive = 0;\n let negative = 0;\n for (let seriesIndex = 0; seriesIndex < seriesCount; seriesIndex += 1) {\n const value = matrix[seriesIndex][categoryIndex] ?? 0;\n if (value >= 0) {\n positive += value;\n } else {\n negative += value;\n }\n }\n maxValue = Math.max(maxValue, positive);\n minValue = Math.min(minValue, negative);\n }\n } else {\n for (const row of matrix) {\n for (const value of row) {\n maxValue = Math.max(maxValue, value);\n minValue = Math.min(minValue, value);\n }\n }\n }\n if (!Number.isFinite(minValue) || !Number.isFinite(maxValue)) {\n minValue = 0;\n maxValue = 1;\n }\n\n const valueDomain = resolveAxisDomainWithChartOverrides(\n chart.valueAxis,\n minValue,\n maxValue,\n true\n );\n minValue = valueDomain.min;\n maxValue = valueDomain.max;\n\n const categoryBandPadding = isHistogramLike\n ? { inner: 0, outer: 0 }\n : resolveCategoryBandPadding(chart.gapWidth);\n const categoryScale = scaleBand<string>()\n .domain(categories)\n .range(isHorizontal ? [plot.top, plot.top + plot.height] : [plot.left, plot.left + plot.width])\n .paddingInner(categoryBandPadding.inner)\n .paddingOuter(categoryBandPadding.outer);\n\n const seriesScale = scaleBand<string>()\n .domain(Array.from({ length: seriesCount }, (_, index) => String(index)))\n .range([0, categoryScale.bandwidth()])\n .paddingInner(isHistogramLike ? 0 : 0.16)\n .paddingOuter(isHistogramLike ? 0 : 0.08);\n const usesSeriesDepthAxis = (\n chart.is3d === true\n && !isHorizontal\n && !isStacked\n && seriesCount > 1\n && chart.seriesAxis != null\n );\n const depthLaneSpread = usesSeriesDepthAxis\n ? clamp(1.26 + seriesCount * 0.16, 1.4, 1.96)\n : 1;\n const depthGridSpanX = usesSeriesDepthAxis && frameOffsets\n ? frameOffsets.depthX * depthLaneSpread\n : 0;\n const depthGridSpanY = usesSeriesDepthAxis && frameOffsets\n ? frameOffsets.depthY * depthLaneSpread\n : 0;\n const depthSlotX = usesSeriesDepthAxis ? depthGridSpanX / Math.max(1, seriesCount) : 0;\n const depthSlotY = usesSeriesDepthAxis ? depthGridSpanY / Math.max(1, seriesCount) : 0;\n const depthBarX = usesSeriesDepthAxis\n ? Math.sign(depthSlotX || frameOffsets?.depthX || 1) * Math.max(8, Math.abs(depthSlotX) * 1.14)\n : frameOffsets?.depthX;\n const depthBarY = usesSeriesDepthAxis\n ? Math.sign(depthSlotY || frameOffsets?.depthY || -1) * Math.max(5.5, Math.abs(depthSlotY) * 1.12)\n : frameOffsets?.depthY;\n\n const shouldReverseValueAxis = chart.valueAxis?.orientation === \"maxMin\";\n const valueScale = scaleLinear()\n .domain([minValue, maxValue])\n .range(\n isHorizontal\n ? (shouldReverseValueAxis ? [plot.left + plot.width, plot.left] : [plot.left, plot.left + plot.width])\n : (shouldReverseValueAxis ? [plot.top, plot.top + plot.height] : [plot.top + plot.height, plot.top])\n );\n\n const ticks = isPercentStacked\n ? buildNumericTickValues(minValue, maxValue, chart.valueAxis?.majorUnit ?? 20)\n : valueDomain.ticks;\n const categoryPositions = categories.map((category) => {\n const bandStart = categoryScale(category) ?? 0;\n return bandStart + categoryScale.bandwidth() / 2;\n });\n\n const bars: BarRect[] = [];\n const positive = Array.from({ length: categoryCount }, () => 0);\n const negative = Array.from({ length: categoryCount }, () => 0);\n\n for (let seriesIndex = 0; seriesIndex < seriesCount; seriesIndex += 1) {\n for (let categoryIndex = 0; categoryIndex < categoryCount; categoryIndex += 1) {\n const value = matrix[seriesIndex][categoryIndex] ?? 0;\n const rawValue = rawMatrix[seriesIndex][categoryIndex] ?? value;\n const pointIndex = shouldReverseCategories ? (categoryCount - 1 - categoryIndex) : categoryIndex;\n const pointStyle = chart.series[seriesIndex]?.dataPointStyles?.find((entry) => entry.index === pointIndex);\n let start = 0;\n let end = value;\n if (isStacked) {\n if (value >= 0) {\n start = positive[categoryIndex];\n positive[categoryIndex] += value;\n end = positive[categoryIndex];\n } else {\n start = negative[categoryIndex];\n negative[categoryIndex] += value;\n end = negative[categoryIndex];\n }\n }\n\n const colors = chartSeriesBarColors(chart, seriesIndex, rawValue, negativeFillMode);\n const isInvertedNegative = rawValue < 0 && chart.series[seriesIndex]?.invertIfNegative === true;\n if (!(isInvertedNegative)) {\n if (variesBarColorsByCategory(chart)) {\n colors.fill = chartPointColor(chart, pointIndex, seriesIndex);\n colors.stroke = colors.fill;\n }\n if (pointStyle?.color) {\n colors.fill = pointStyle.color;\n if (!pointStyle.lineColor) {\n colors.stroke = pointStyle.color;\n }\n }\n if (pointStyle?.lineColor) {\n colors.stroke = pointStyle.lineColor;\n }\n }\n if (isInvertedNegative && isPercentStacked && chart.is3d) {\n colors.fill = \"#ffffff\";\n }\n const category = categories[categoryIndex];\n const categoryStart = categoryScale(category) ?? 0;\n const barThickness = usesSeriesDepthAxis\n ? Math.max(7, categoryScale.bandwidth() * 0.4)\n : isHistogramLike\n ? categoryScale.bandwidth()\n : isStacked\n ? categoryScale.bandwidth()\n : seriesScale.bandwidth();\n const barOffset = usesSeriesDepthAxis\n ? Math.max(0, (categoryScale.bandwidth() - barThickness) * 0.5)\n : isHistogramLike\n ? 0\n : isStacked\n ? 0\n : (seriesScale(String(seriesIndex)) ?? 0);\n const depthOffsetX = usesSeriesDepthAxis ? depthSlotX * seriesIndex : 0;\n const depthOffsetY = usesSeriesDepthAxis ? depthSlotY * seriesIndex : 0;\n const depthOrder = depthOffsetX * (frameOffsets?.depthX ?? 0) + depthOffsetY * (frameOffsets?.depthY ?? 0);\n const shapeTaper = normalized3dShape === \"pyramid\"\n ? 0.94\n : normalized3dShape === \"cone\"\n ? 1\n : 0;\n let topScale = 1;\n let bottomScale = 1;\n if (chart.is3d && shapeTaper > 0) {\n const scaleAt = (ratio: number) => {\n const clampedRatio = clamp(ratio, 0, 1);\n const taperedRatio = normalized3dShape === \"cone\"\n ? Math.pow(clampedRatio, isHorizontal ? 1.85 : 1.08)\n : clampedRatio;\n return clamp(1 - (taperedRatio * shapeTaper), normalized3dShape === \"cone\" ? 0 : 0.04, 1);\n };\n if (rawValue >= 0) {\n const total = Math.max(1e-6, isStacked ? positiveTotals[categoryIndex] : Math.abs(rawValue));\n bottomScale = scaleAt(isStacked ? start / total : 0);\n topScale = scaleAt(isStacked ? end / total : 1);\n } else {\n const total = Math.max(1e-6, isStacked ? negativeTotals[categoryIndex] : Math.abs(rawValue));\n topScale = scaleAt(isStacked ? Math.abs(start) / total : 0);\n bottomScale = scaleAt(isStacked ? Math.abs(end) / total : 1);\n }\n }\n\n if (isHorizontal) {\n const x1 = valueScale(start);\n const x2 = valueScale(end);\n const maxPositive = positiveTotals[categoryIndex] ?? 0;\n const maxNegative = negativeTotals[categoryIndex] ?? 0;\n bars.push({\n capEnd: !isStacked || (rawValue >= 0\n ? Math.abs(end - maxPositive) < 1e-6\n : Math.abs(end - maxNegative) < 1e-6),\n capStart: !isStacked || Math.abs(start) < 1e-6,\n bottomScale,\n categoryIndex,\n color: colors.fill,\n depthOrder,\n depthOffsetX,\n depthOffsetY,\n height: Math.max(1, barThickness),\n isHorizontal: true,\n key: `bar-${seriesIndex}-${categoryIndex}`,\n left: Math.min(x1, x2),\n depthX: usesSeriesDepthAxis ? depthBarX : frameOffsets?.depthX,\n depthY: usesSeriesDepthAxis ? depthBarY : frameOffsets?.depthY,\n shape3d: normalized3dShape,\n seriesIndex,\n stroke: colors.stroke,\n strokeWidth: colors.strokeWidth,\n topScale,\n top: categoryStart + barOffset,\n invertedNegative: isInvertedNegative,\n value: rawValue,\n width: Math.max(1, Math.abs(x2 - x1))\n });\n } else {\n const y1 = valueScale(start);\n const y2 = valueScale(end);\n const maxPositive = positiveTotals[categoryIndex] ?? 0;\n const maxNegative = negativeTotals[categoryIndex] ?? 0;\n bars.push({\n capEnd: !isStacked || (rawValue >= 0\n ? Math.abs(end - maxPositive) < 1e-6\n : Math.abs(end - maxNegative) < 1e-6),\n capStart: !isStacked || Math.abs(start) < 1e-6,\n bottomScale,\n categoryIndex,\n color: colors.fill,\n depthOrder,\n depthOffsetX,\n depthOffsetY,\n height: Math.max(1, Math.abs(y2 - y1)),\n isHorizontal: false,\n key: `bar-${seriesIndex}-${categoryIndex}`,\n left: categoryStart + barOffset,\n depthX: usesSeriesDepthAxis ? depthBarX : frameOffsets?.depthX,\n depthY: usesSeriesDepthAxis ? depthBarY : frameOffsets?.depthY,\n shape3d: normalized3dShape,\n seriesIndex,\n stroke: colors.stroke,\n strokeWidth: colors.strokeWidth,\n topScale,\n top: Math.min(y1, y2),\n invertedNegative: isInvertedNegative,\n value: rawValue,\n width: Math.max(1, barThickness)\n });\n }\n }\n }\n\n const renderedBars = chart.is3d && isStacked\n ? bars.slice().sort((left, right) => {\n if (left.categoryIndex !== right.categoryIndex) {\n return left.categoryIndex - right.categoryIndex;\n }\n const leftNegative = left.value < 0 ? 0 : 1;\n const rightNegative = right.value < 0 ? 0 : 1;\n if (leftNegative !== rightNegative) {\n return leftNegative - rightNegative;\n }\n if (isHorizontal) {\n if (left.left !== right.left) {\n return left.left - right.left;\n }\n return left.seriesIndex - right.seriesIndex;\n }\n if (left.top !== right.top) {\n return right.top - left.top;\n }\n return left.seriesIndex - right.seriesIndex;\n })\n : bars;\n const sortedBars = usesSeriesDepthAxis\n ? renderedBars.slice().sort((left, right) => {\n if ((left.depthOrder ?? 0) !== (right.depthOrder ?? 0)) {\n return (right.depthOrder ?? 0) - (left.depthOrder ?? 0);\n }\n if (left.categoryIndex !== right.categoryIndex) {\n return left.categoryIndex - right.categoryIndex;\n }\n return left.top - right.top;\n })\n : renderedBars;\n\n const useVertical3dGradient = chart.is3d && !isHorizontal;\n const gradientByColor = new Map<string, string>();\n if (useVertical3dGradient) {\n for (const bar of renderedBars) {\n if (!bar.color || bar.color === \"none\" || bar.color.startsWith(\"url(\")) {\n continue;\n }\n if (!gradientByColor.has(bar.color)) {\n gradientByColor.set(\n bar.color,\n `bar3d-front-${chart.id}-${gradientByColor.size}`.replace(/[^A-Za-z0-9_-]/g, \"-\")\n );\n }\n bar.gradientId = gradientByColor.get(bar.color);\n }\n }\n\n const axisNode = renderCartesianAxes(\n chart,\n palette,\n plot,\n isHorizontal,\n categories,\n categoryPositions,\n ticks,\n (value) => valueScale(value),\n isPercentStacked ? formatPercentTickValue : formatTickValue\n );\n const depthAxisColor = chart.axisLineColor ?? chart.chartAreaBorderColor ?? palette.border;\n const depthGridColor = lightenColor(depthAxisColor, 0.48);\n const frameDepthX = usesSeriesDepthAxis ? depthGridSpanX : (frameOffsets?.depthX ?? 0);\n const frameDepthY = usesSeriesDepthAxis ? depthGridSpanY : (frameOffsets?.depthY ?? 0);\n const depthAxisNode = usesSeriesDepthAxis && frameOffsets ? (\n <g>\n {Array.from({ length: categoryCount + 1 }, (_, boundaryIndex) => {\n const x = plot.left + ((boundaryIndex / Math.max(1, categoryCount)) * plot.width);\n return (\n <line\n key={`bar3d-floor-x-${boundaryIndex}`}\n stroke={depthGridColor}\n strokeWidth={0.9}\n x1={x}\n x2={x + depthGridSpanX}\n y1={plot.top + plot.height}\n y2={plot.top + plot.height + depthGridSpanY}\n />\n );\n })}\n {Array.from({ length: seriesCount + 1 }, (_, boundaryIndex) => {\n const ratio = boundaryIndex / Math.max(1, seriesCount);\n const offsetX = depthGridSpanX * ratio;\n const offsetY = depthGridSpanY * ratio;\n return (\n <line\n key={`bar3d-floor-z-${boundaryIndex}`}\n stroke={depthGridColor}\n strokeWidth={0.9}\n x1={plot.left + offsetX}\n x2={plot.left + plot.width + offsetX}\n y1={plot.top + plot.height + offsetY}\n y2={plot.top + plot.height + offsetY}\n />\n );\n })}\n {chart.series.map((series, seriesIndex) => {\n const ratio = (seriesIndex + 0.5) / Math.max(1, seriesCount);\n const x = plot.left + plot.width + depthGridSpanX * ratio;\n const y = plot.top + plot.height + depthGridSpanY * ratio;\n return (\n <text\n key={`bar3d-ser-label-${seriesIndex}`}\n fill={resolveChartAxisTextColor(chart)}\n fontSize={10}\n textAnchor=\"start\"\n x={x + 7}\n y={y + 3}\n >\n {series.name ?? `Series ${seriesIndex + 1}`}\n </text>\n );\n })}\n </g>\n ) : null;\n\n const frameNode = chart.is3d && frameOffsets ? (\n <g>\n <polygon\n fill={lightenColor(chart.chartAreaFillColor ?? palette.surface, 0.05)}\n points={`${plot.left},${plot.top + plot.height} ${plot.left + plot.width},${plot.top + plot.height} ${plot.left + plot.width + frameDepthX},${plot.top + plot.height + frameDepthY} ${plot.left + frameDepthX},${plot.top + plot.height + frameDepthY}`}\n stroke={lightenColor(chart.axisLineColor ?? palette.border, 0.2)}\n strokeWidth={1}\n />\n <polygon\n fill={lightenColor(chart.chartAreaFillColor ?? palette.surface, 0.12)}\n points={`${plot.left},${plot.top} ${plot.left + plot.width},${plot.top} ${plot.left + plot.width + frameDepthX},${plot.top + frameDepthY} ${plot.left + frameDepthX},${plot.top + frameDepthY}`}\n stroke={lightenColor(chart.axisLineColor ?? palette.border, 0.2)}\n strokeWidth={1}\n />\n </g>\n ) : null;\n\n return (\n <g>\n {useVertical3dGradient && gradientByColor.size > 0 ? (\n <defs>\n {Array.from(gradientByColor.entries()).map(([color, id]) => (\n <linearGradient id={id} key={id} x1=\"0%\" x2=\"0%\" y1=\"0%\" y2=\"100%\">\n <stop offset=\"0%\" stopColor={lightenColor(color, 0.28)} />\n <stop offset=\"42%\" stopColor={lightenColor(color, 0.12)} />\n <stop offset=\"100%\" stopColor={darkenColor(color, 0.1)} />\n </linearGradient>\n ))}\n </defs>\n ) : null}\n {axisNode}\n {frameNode}\n {depthAxisNode}\n {chart.is3d\n ? sortedBars.map((bar) => (\n <g key={`bar-hit-${bar.key}`} {...barChartElementDataProps(bar.seriesIndex, bar.categoryIndex)}>\n {renderExtrudedRect(bar)}\n </g>\n ))\n : renderedBars.map((bar) => (\n <rect\n {...barChartElementDataProps(bar.seriesIndex, bar.categoryIndex)}\n key={bar.key}\n fill={bar.color}\n height={bar.height}\n stroke={isHistogramLike ? \"none\" : bar.stroke}\n strokeWidth={isHistogramLike ? 0 : bar.strokeWidth}\n width={bar.width}\n x={bar.left}\n y={bar.top}\n />\n ))}\n {renderedBars.map((bar) => (\n isSelectedChartPoint(selectedChartElement, chart.id, bar.seriesIndex, bar.categoryIndex)\n || (\n isSelectedChartSeries(selectedChartElement, chart.id, bar.seriesIndex)\n && selectedChartElement?.kind !== \"point\"\n )\n ? renderSelectionRectHandles(`bar-selection-${bar.key}`, bar.left, bar.top, bar.width, bar.height)\n : null\n ))}\n </g>\n );\n}\n\nfunction renderLineOrAreaChart(chart: XlsxChart, palette: ChartRendererPalette, layout: ChartLayout, chartType: string, selectedChartElement?: XlsxChartElementSelection | null) {\n if (chart.series.length === 0) {\n return null;\n }\n const categories = getCategoryLabels(chart);\n if (categories.length === 0) {\n return null;\n }\n const plot = layout.plot;\n const displayBlanksAs = chart.displayBlanksAs;\n const isAreaChart = chartType === \"Area\" || chartType === \"AreaStacked\" || chartType === \"AreaPercentStacked\";\n const isStackedArea = chartType === \"AreaStacked\" || chartType === \"AreaPercentStacked\";\n const isStackedLine = chartType === \"LineStacked\" || chartType === \"LinePercentStacked\";\n const isStackedSeries = isStackedArea || isStackedLine;\n const isPercentStackedSeries = chartType === \"AreaPercentStacked\" || chartType === \"LinePercentStacked\";\n const resolvedValuesBySeries = chart.series.map((series) => (\n categories.map((_, categoryIndex) => resolveRenderableSeriesValue(series.values[categoryIndex], displayBlanksAs))\n ));\n\n type SeriesPoint = {\n defined: boolean;\n y: number | null;\n y0: number | null;\n y1: number | null;\n };\n\n const stackedPointsBySeries: SeriesPoint[][] = isStackedSeries\n ? (() => {\n const positive = Array.from({ length: categories.length }, () => 0);\n const negative = Array.from({ length: categories.length }, () => 0);\n const categoryTotals = isPercentStackedSeries\n ? categories.map((_, categoryIndex) => {\n const total = resolvedValuesBySeries.reduce((sum, seriesValues) => (\n sum + (seriesValues[categoryIndex] ?? 0)\n ), 0);\n return Math.abs(total) < 1e-9 ? 1 : total;\n })\n : null;\n return chart.series.map((_, seriesIndex) => (\n categories.map((_, categoryIndex) => {\n const rawValue = resolvedValuesBySeries[seriesIndex]?.[categoryIndex] ?? null;\n if (rawValue == null) {\n return { defined: false, y: null, y0: null, y1: null };\n }\n const value = isPercentStackedSeries\n ? (rawValue / (categoryTotals?.[categoryIndex] ?? 1)) * 100\n : rawValue;\n if (value >= 0) {\n const start = positive[categoryIndex];\n const end = start + value;\n positive[categoryIndex] = end;\n return { defined: true, y: end, y0: start, y1: end };\n }\n const start = negative[categoryIndex];\n const end = start + value;\n negative[categoryIndex] = end;\n return { defined: true, y: end, y0: start, y1: end };\n })\n ));\n })()\n : chart.series.map((_, seriesIndex) => (\n categories.map((_, categoryIndex) => {\n const value = resolvedValuesBySeries[seriesIndex]?.[categoryIndex] ?? null;\n return {\n defined: value != null,\n y: value,\n y0: null,\n y1: value\n };\n })\n ));\n\n const stackedExtents = stackedPointsBySeries\n .flatMap((seriesPoints) => (\n seriesPoints.flatMap((point) => (\n point.defined\n ? [point.y0, point.y1].filter((value): value is number => value != null && Number.isFinite(value))\n : []\n ))\n ));\n if (stackedExtents.length === 0) {\n return null;\n }\n let minValue = Math.min(...stackedExtents);\n let maxValue = Math.max(...stackedExtents);\n if (isAreaChart) {\n minValue = Math.min(0, minValue);\n } else if ((chartType === \"Line\" || isStackedLine) && chart.valueAxis?.crosses === \"autoZero\") {\n minValue = Math.min(0, minValue);\n }\n if (isPercentStackedSeries) {\n const explicitMin = typeof chart.valueAxis?.min === \"number\" && Number.isFinite(chart.valueAxis.min)\n ? Number(chart.valueAxis.min)\n : Math.min(0, minValue);\n const explicitMax = typeof chart.valueAxis?.max === \"number\" && Number.isFinite(chart.valueAxis.max)\n ? Number(chart.valueAxis.max)\n : Math.max(100, maxValue);\n minValue = explicitMin;\n maxValue = explicitMax <= explicitMin ? explicitMin + 1 : explicitMax;\n } else {\n const valueDomain = resolveAxisDomainWithChartOverrides(\n chart.valueAxis,\n minValue,\n maxValue,\n isAreaChart || chart.valueAxis?.crosses === \"autoZero\"\n );\n minValue = valueDomain.min;\n maxValue = valueDomain.max;\n }\n\n const xScale = scalePoint<string>()\n .domain(categories)\n .range([plot.left, plot.left + plot.width]);\n const yScale = scaleLinear()\n .domain([minValue, maxValue])\n .range([plot.top + plot.height, plot.top]);\n\n const ticks = isPercentStackedSeries\n ? buildNumericTickValues(minValue, maxValue, chart.valueAxis?.majorUnit ?? 20)\n : resolveAxisDomainWithChartOverrides(\n chart.valueAxis,\n minValue,\n maxValue,\n isAreaChart || chart.valueAxis?.crosses === \"autoZero\"\n ).ticks;\n const categoryPositions = categories.map((category) => xScale(category) ?? plot.left);\n\n const curve: CurveFactory = curveLinear;\n const areaBaseline = yScale(Math.max(minValue, 0));\n const plotPointsBySeries = chart.series.map((_, seriesIndex) => (\n categories.map((category, categoryIndex) => {\n const point = stackedPointsBySeries[seriesIndex]?.[categoryIndex] ?? {\n defined: false,\n y: null,\n y0: null,\n y1: null\n };\n return {\n defined: point.defined,\n x: xScale(category) ?? plot.left,\n y: point.y,\n y0: point.y0,\n y1: point.y1\n };\n })\n ));\n\n if (chart.is3d) {\n return renderLineOrAreaChart3d(\n chart,\n palette,\n layout,\n categories,\n stackedPointsBySeries,\n minValue,\n maxValue,\n isAreaChart,\n isStackedSeries,\n selectedChartElement\n );\n }\n\n const rawRecord = chart.raw && typeof chart.raw === \"object\"\n ? chart.raw as Record<string, unknown>\n : null;\n const dropLinesRecord = rawRecord?.dropLines && typeof rawRecord.dropLines === \"object\"\n ? rawRecord.dropLines as Record<string, unknown>\n : null;\n const highLowLinesRecord = rawRecord?.highLowLines && typeof rawRecord.highLowLines === \"object\"\n ? rawRecord.highLowLines as Record<string, unknown>\n : null;\n const upDownBarsRecord = rawRecord?.upDownBars && typeof rawRecord.upDownBars === \"object\"\n ? rawRecord.upDownBars as Record<string, unknown>\n : null;\n const dropLineColor = normalizeRendererHexColor((dropLinesRecord?.shapeProperties as Record<string, unknown> | undefined)?.lineColorHex)\n ?? lightenColor(chart.axisLineColor ?? chart.chartAreaBorderColor ?? palette.border, 0.45);\n const highLowLineColor = normalizeRendererHexColor((highLowLinesRecord?.shapeProperties as Record<string, unknown> | undefined)?.lineColorHex)\n ?? chart.axisLineColor\n ?? chart.chartAreaBorderColor\n ?? palette.border;\n const upDownGapWidth = typeof upDownBarsRecord?.gapWidth === \"number\" && Number.isFinite(upDownBarsRecord.gapWidth)\n ? upDownBarsRecord.gapWidth\n : 150;\n const categoryStep = categoryPositions.length >= 2\n ? Math.min(...categoryPositions.slice(1).map((position, index) => Math.abs(position - (categoryPositions[index] ?? 0))).filter((value) => value > 0))\n : plot.width;\n const upDownBarWidth = clamp(categoryStep * (1 - resolveCategoryBandPadding(upDownGapWidth).inner) * 0.82, 3, 28);\n\n return (\n <g>\n {renderCartesianAxes(\n chart,\n palette,\n plot,\n false,\n categories,\n categoryPositions,\n ticks,\n (value) => yScale(value)\n )}\n {!isAreaChart && !isStackedSeries && highLowLinesRecord\n ? categories.map((_, categoryIndex) => {\n const yValues = plotPointsBySeries\n .map((seriesPoints) => seriesPoints[categoryIndex]?.y)\n .filter((value): value is number => value != null && Number.isFinite(value));\n if (yValues.length < 2) {\n return null;\n }\n const x = categoryPositions[categoryIndex] ?? plot.left;\n return (\n <line\n key={`high-low-${categoryIndex}`}\n stroke={highLowLineColor}\n strokeWidth={1}\n x1={x}\n x2={x}\n y1={yScale(Math.min(...yValues))}\n y2={yScale(Math.max(...yValues))}\n />\n );\n })\n : null}\n {!isAreaChart && !isStackedSeries && upDownBarsRecord && plotPointsBySeries.length >= 2\n ? categories.map((_, categoryIndex) => {\n const first = plotPointsBySeries[0]?.[categoryIndex];\n const second = plotPointsBySeries[plotPointsBySeries.length - 1]?.[categoryIndex];\n if (!first || !second || first.y == null || second.y == null) {\n return null;\n }\n const top = yScale(Math.max(first.y, second.y));\n const bottom = yScale(Math.min(first.y, second.y));\n const isUpBar = second.y >= first.y;\n const fill = isUpBar ? darkenColor(highLowLineColor, 0.12) : \"#c0504d\";\n return (\n <rect\n key={`up-down-${categoryIndex}`}\n fill={fill}\n fillOpacity={0.92}\n height={Math.max(1, bottom - top)}\n stroke={darkenColor(fill, 0.18)}\n strokeWidth={1}\n width={upDownBarWidth}\n x={(categoryPositions[categoryIndex] ?? plot.left) - upDownBarWidth / 2}\n y={top}\n />\n );\n })\n : null}\n {chart.series.map((series, seriesIndex) => {\n const points = plotPointsBySeries[seriesIndex] ?? [];\n const lineStrokePoints = displayBlanksAs === \"span\"\n ? points.filter((point) => point.y != null)\n : points;\n const linePath = d3Line<{ x: number; y: number | null }>()\n .defined((point) => point.y != null)\n .x((point) => point.x)\n .y((point) => yScale(point.y ?? 0))\n .curve(curve)(lineStrokePoints) ?? \"\";\n\n const areaPath = isAreaChart\n ? d3Area<{ x: number; y: number | null; y0: number | null; y1: number | null }>()\n .defined((point) => (\n isStackedSeries\n ? point.y0 != null && point.y1 != null\n : point.y != null\n ))\n .x((point) => point.x)\n .y0((point) => (\n isStackedSeries\n ? yScale(point.y0 ?? 0)\n : areaBaseline\n ))\n .y1((point) => yScale((isStackedSeries ? point.y1 : point.y) ?? 0))\n .curve(curve)(points) ?? \"\"\n : \"\";\n\n const seriesFillColor = typeof series.shapeProperties?.xmlFillColor === \"string\"\n ? series.shapeProperties.xmlFillColor\n : chartSeriesColor(chart, seriesIndex);\n return (\n <g key={`line-series-${seriesIndex}`}>\n {!isAreaChart && !isStackedSeries && dropLinesRecord\n ? points.map((point, pointIndex) => (\n point.y == null ? null : (\n <line\n key={`drop-line-${seriesIndex}-${pointIndex}`}\n stroke={dropLineColor}\n strokeWidth={1}\n x1={point.x}\n x2={point.x}\n y1={yScale(point.y)}\n y2={areaBaseline}\n />\n )\n ))\n : null}\n {isAreaChart ? (\n <path\n {...chartElementDataProps(seriesIndex)}\n d={areaPath}\n fill={seriesFillColor}\n fillOpacity={1}\n stroke=\"none\"\n />\n ) : null}\n <path\n {...chartElementDataProps(seriesIndex)}\n d={linePath}\n fill=\"none\"\n stroke={series.shapeProperties?.xmlLineHidden === true ? \"none\" : chartSeriesStrokeColor(chart, seriesIndex)}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={Math.max(1.5, series.lineWidthPx ?? 2)}\n />\n {points.map((point, pointIndex) => (\n point.y == null || normalizeChartMarkerSymbol(series.markerSymbol) === \"none\" ? null : (\n <path\n {...chartElementDataProps(seriesIndex, pointIndex)}\n key={`line-marker-${seriesIndex}-${pointIndex}`}\n d={markerSymbolPath(normalizeChartMarkerSymbol(series.markerSymbol), markerRadiusPx(series.markerSize))}\n transform={`translate(${point.x}, ${yScale(point.y)})`}\n fill={series.markerColor ?? chartSeriesColor(chart, seriesIndex)}\n stroke={series.markerLineColor ?? chart.chartAreaFillColor ?? chartSeriesStrokeColor(chart, seriesIndex)}\n strokeWidth={1}\n />\n )\n ))}\n {points.map((point, pointIndex) => (\n point.y != null && (\n isSelectedChartPoint(selectedChartElement, chart.id, seriesIndex, pointIndex)\n || (\n isSelectedChartSeries(selectedChartElement, chart.id, seriesIndex)\n && selectedChartElement?.kind !== \"point\"\n )\n )\n ? isAreaChart\n ? renderSelectionPointHandles(`area-selection-${seriesIndex}-${pointIndex}`, [{ x: point.x, y: yScale(point.y) }])\n : renderSelectionRectHandles(\n `line-selection-${seriesIndex}-${pointIndex}`,\n point.x - 4,\n yScale(point.y) - 4,\n 8,\n 8\n )\n : null\n ))}\n </g>\n );\n })}\n </g>\n );\n}\n\nfunction renderComboChart(chart: XlsxChart, palette: ChartRendererPalette, layout: ChartLayout, selectedChartElement?: XlsxChartElementSelection | null) {\n const groups = buildComboGroups(chart);\n const columnGroup = groups.find((group) => group.chartType.startsWith(\"Column\"));\n const lineGroup = groups.find((group) => group.chartType.startsWith(\"Line\"));\n if (!columnGroup || !lineGroup) {\n return null;\n }\n\n const primaryChart: XlsxChart = {\n ...chart,\n categoryAxis: columnGroup.categoryAxis ?? chart.categoryAxis,\n chartType: columnGroup.chartType,\n dataLabels: undefined,\n is3d: columnGroup.is3d ?? false,\n series: columnGroup.series,\n valueAxis: columnGroup.valueAxis ?? chart.valueAxis\n };\n const categories = getCategoryLabels(primaryChart);\n if (categories.length === 0) {\n return null;\n }\n\n const plot = layout.plot;\n const groupGapWidth = typeof columnGroup.raw?.gapWidth === \"number\" && Number.isFinite(columnGroup.raw.gapWidth)\n ? columnGroup.raw.gapWidth\n : columnGroup.gapWidth ?? chart.gapWidth;\n const histogramColumns = columnGroup.series.some((series) => isHistogramLikeSeries(series));\n const categoryBandPadding = histogramColumns\n ? { inner: 0, outer: 0 }\n : resolveCategoryBandPadding(groupGapWidth);\n const categoryScale = scaleBand<string>()\n .domain(categories)\n .range([plot.left, plot.left + plot.width])\n .paddingInner(categoryBandPadding.inner)\n .paddingOuter(categoryBandPadding.outer);\n const seriesScale = scaleBand<string>()\n .domain(Array.from({ length: columnGroup.series.length }, (_, index) => String(index)))\n .range([0, categoryScale.bandwidth()])\n .paddingInner(histogramColumns ? 0 : 0.16)\n .paddingOuter(histogramColumns ? 0 : 0.08);\n const categoryPositions = categories.map((category) => (\n (categoryScale(category) ?? plot.left) + categoryScale.bandwidth() / 2\n ));\n const resolveGlobalSeriesIndex = (series: XlsxChartSeries) => {\n const index = chart.series.findIndex((candidate) => candidate.id === series.id);\n return index >= 0 ? index : 0;\n };\n\n const primaryValues = columnGroup.series.flatMap((series) => (\n series.values.map((value) => safeNumber(value)).filter((value): value is number => value != null)\n ));\n const secondaryValues = lineGroup.series.flatMap((series) => (\n series.values.map((value) => safeNumber(value)).filter((value): value is number => value != null)\n ));\n if (primaryValues.length === 0 || secondaryValues.length === 0) {\n return null;\n }\n\n const primaryDomain = resolveNumericAxisDomain(\n typeof columnGroup.valueAxis?.min === \"number\" ? columnGroup.valueAxis.min : Math.min(...primaryValues),\n typeof columnGroup.valueAxis?.max === \"number\" ? columnGroup.valueAxis.max : Math.max(...primaryValues),\n columnGroup.valueAxis?.majorUnit,\n true\n );\n const secondaryDomain = resolveNumericAxisDomain(\n typeof lineGroup.valueAxis?.min === \"number\" ? lineGroup.valueAxis.min : Math.min(...secondaryValues),\n typeof lineGroup.valueAxis?.max === \"number\" ? lineGroup.valueAxis.max : Math.max(...secondaryValues),\n lineGroup.valueAxis?.majorUnit,\n false\n );\n const primaryScale = scaleLinear()\n .domain([primaryDomain.min, primaryDomain.max])\n .range([plot.top + plot.height, plot.top]);\n const secondaryScale = scaleLinear()\n .domain([secondaryDomain.min, secondaryDomain.max])\n .range([plot.top + plot.height, plot.top]);\n const axisColor = chart.axisLineColor ?? chart.chartAreaBorderColor ?? palette.border;\n const labelColor = resolveChartAxisTextColor(chart);\n\n return (\n <g>\n {renderCartesianAxes(\n primaryChart,\n palette,\n plot,\n false,\n categories,\n categoryPositions,\n primaryDomain.ticks,\n (value) => primaryScale(value)\n )}\n {lineGroup.valueAxis?.delete !== true && lineGroup.valueAxis?.labelPosition !== \"none\" ? secondaryDomain.ticks.map((tick) => {\n const y = secondaryScale(tick);\n return (\n <text\n key={`combo-secondary-tick-${tick}`}\n fill={labelColor}\n fontSize={10}\n textAnchor=\"start\"\n x={plot.left + plot.width + 6}\n y={y + 3}\n >\n {formatTickValue(tick)}\n </text>\n );\n }) : null}\n {lineGroup.valueAxis?.delete !== true ? <line\n stroke={axisColor}\n strokeWidth={1.2}\n x1={plot.left + plot.width}\n x2={plot.left + plot.width}\n y1={plot.top}\n y2={plot.top + plot.height}\n /> : null}\n {columnGroup.series.flatMap((series, seriesIndex) => categories.map((category, categoryIndex) => {\n const globalSeriesIndex = resolveGlobalSeriesIndex(series);\n const value = safeNumber(series.values[categoryIndex]) ?? 0;\n const categoryStart = categoryScale(category) ?? plot.left;\n const barWidth = Math.max(1, histogramColumns ? categoryScale.bandwidth() : seriesScale.bandwidth());\n const x = categoryStart + (histogramColumns ? 0 : (seriesScale(String(seriesIndex)) ?? 0));\n const y = primaryScale(Math.max(0, value));\n const zeroY = primaryScale(0);\n const height = Math.max(1, Math.abs(zeroY - primaryScale(value)));\n const selected = isSelectedChartPoint(selectedChartElement, chart.id, globalSeriesIndex, categoryIndex)\n || (\n isSelectedChartSeries(selectedChartElement, chart.id, globalSeriesIndex)\n && selectedChartElement?.kind !== \"point\"\n );\n return (\n <React.Fragment key={`combo-bar-${seriesIndex}-${categoryIndex}`}>\n <rect\n {...barChartElementDataProps(globalSeriesIndex, categoryIndex)}\n fill={series.color ?? series.lineColor ?? chartSeriesColor(primaryChart, seriesIndex)}\n height={height}\n stroke={selected ? \"#64748b\" : (histogramColumns ? \"none\" : (series.lineColor ?? series.color ?? chartSeriesStrokeColor(primaryChart, seriesIndex)))}\n strokeWidth={selected ? 2 : (histogramColumns ? 0 : 1)}\n width={barWidth}\n x={x}\n y={Math.min(y, zeroY)}\n />\n {selected\n ? renderSelectionRectHandles(\n `combo-bar-selection-${globalSeriesIndex}-${categoryIndex}`,\n x,\n Math.min(y, zeroY),\n barWidth,\n height\n )\n : null}\n </React.Fragment>\n );\n }))}\n {lineGroup.series.map((series, seriesIndex) => {\n const globalSeriesIndex = resolveGlobalSeriesIndex(series);\n const points = categories.map((category, categoryIndex) => ({\n x: (categoryScale(category) ?? plot.left) + categoryScale.bandwidth() / 2,\n y: safeNumber(series.values[categoryIndex])\n }));\n const lineStrokePoints = chart.displayBlanksAs === \"span\"\n ? points.filter((point) => point.y != null)\n : points;\n const path = d3Line<{ x: number; y: number | null }>()\n .defined((point) => point.y != null)\n .x((point) => point.x)\n .y((point) => secondaryScale(point.y ?? 0))\n .curve(curveLinear)(lineStrokePoints) ?? \"\";\n return (\n <g key={`combo-line-${seriesIndex}`}>\n <path\n {...chartElementDataProps(globalSeriesIndex)}\n d={path}\n fill=\"none\"\n stroke={series.lineColor ?? series.color ?? chartSeriesStrokeColor(chart, columnGroup.series.length + seriesIndex)}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={Math.max(1.5, series.lineWidthPx ?? 2)}\n />\n {points.map((point, pointIndex) => (\n point.y == null || normalizeChartMarkerSymbol(series.markerSymbol) === \"none\" ? null : (\n <path\n {...chartElementDataProps(globalSeriesIndex, pointIndex)}\n d={markerSymbolPath(normalizeChartMarkerSymbol(series.markerSymbol), markerRadiusPx(series.markerSize))}\n fill={series.markerColor ?? series.color ?? series.lineColor ?? chartSeriesColor(chart, columnGroup.series.length + seriesIndex)}\n key={`combo-line-marker-${seriesIndex}-${pointIndex}`}\n stroke={series.markerLineColor ?? chart.chartAreaFillColor ?? \"#ffffff\"}\n strokeWidth={1}\n transform={`translate(${point.x}, ${secondaryScale(point.y)})`}\n />\n )\n ))}\n {points.map((point, pointIndex) => (\n point.y != null && isSelectedChartPointOrSeries(selectedChartElement, chart.id, globalSeriesIndex, pointIndex)\n ? renderSelectionRectHandles(\n `combo-line-selection-${globalSeriesIndex}-${pointIndex}`,\n point.x - 4,\n secondaryScale(point.y) - 4,\n 8,\n 8\n )\n : null\n ))}\n </g>\n );\n })}\n </g>\n );\n}\n\nfunction renderScatterChart(chart: XlsxChart, palette: ChartRendererPalette, layout: ChartLayout, smooth: boolean, selectedChartElement?: XlsxChartElementSelection | null) {\n const plot = layout.plot;\n const rawRecord = chart.raw && typeof chart.raw === \"object\"\n ? chart.raw as Record<string, unknown>\n : null;\n const scatterStyle = typeof chart.scatterStyle === \"string\"\n ? chart.scatterStyle\n : rawRecord && typeof rawRecord.scatterStyle === \"string\"\n ? rawRecord.scatterStyle\n : undefined;\n const styleDrawsLine = scatterStyle\n ? scatterStyle === \"line\" || scatterStyle === \"lineMarker\" || scatterStyle === \"smooth\" || scatterStyle === \"smoothMarker\"\n : chart.chartType !== \"Scatter\";\n const styleShowsMarkers = scatterStyle\n ? scatterStyle === \"marker\" || scatterStyle === \"lineMarker\" || scatterStyle === \"smoothMarker\"\n : true;\n const styleUsesSmoothCurve = scatterStyle\n ? scatterStyle === \"smooth\" || scatterStyle === \"smoothMarker\"\n : smooth;\n const pointsBySeries = chart.series.map((series) => {\n const yLength = series.values.length;\n const directXValues = Array.from({ length: yLength }, (_, index) => coerceLooseNumber(series.categories[index]));\n\n let resolvedXValues = directXValues;\n let usesSyntheticIndex = false;\n if (directXValues.filter((value) => value != null).length < Math.max(2, yLength - 1)) {\n const categories = series.categories ?? [];\n const pairedXValues = Array.from({ length: yLength }, (_, index) => {\n const candidates = [\n categories[index],\n categories[index * 2],\n categories[index * 2 + 1],\n categories[index + 1]\n ];\n for (const candidate of candidates) {\n const parsed = coerceLooseNumber(candidate);\n if (parsed != null) {\n return parsed;\n }\n }\n return null;\n });\n if (pairedXValues.filter((value) => value != null).length >= 2) {\n resolvedXValues = pairedXValues;\n } else {\n const numericPool = categories\n .map((entry) => coerceLooseNumber(entry))\n .filter((value): value is number => value != null);\n if (numericPool.length >= 2) {\n resolvedXValues = Array.from(\n { length: yLength },\n (_, index) => numericPool[index] ?? numericPool[numericPool.length - 1] ?? null\n );\n } else {\n usesSyntheticIndex = true;\n resolvedXValues = Array.from({ length: yLength }, (_, index) => index + 1);\n }\n }\n }\n\n const points = series.values.map((value, index) => {\n const x = coerceLooseNumber(resolvedXValues[index]);\n const y = safeNumber(value);\n return x == null || y == null ? null : { x, y };\n }).filter((point): point is { x: number; y: number } => point != null);\n return {\n pointCount: yLength,\n points,\n series,\n usesSyntheticIndex\n };\n });\n\n const allX = pointsBySeries.flatMap((series) => series.points.map((point) => point.x));\n const allY = pointsBySeries.flatMap((series) => series.points.map((point) => point.y));\n if (allX.length === 0 || allY.length === 0) {\n return null;\n }\n\n const hasExplicitMinX = typeof chart.categoryAxis?.min === \"number\" && Number.isFinite(chart.categoryAxis.min);\n const hasExplicitMaxX = typeof chart.categoryAxis?.max === \"number\" && Number.isFinite(chart.categoryAxis.max);\n const hasExplicitMinY = typeof chart.valueAxis?.min === \"number\" && Number.isFinite(chart.valueAxis.min);\n const hasExplicitMaxY = typeof chart.valueAxis?.max === \"number\" && Number.isFinite(chart.valueAxis.max);\n const hasSyntheticIndexAxis = pointsBySeries.some((series) => series.usesSyntheticIndex);\n const syntheticPointCount = Math.max(0, ...pointsBySeries.map((series) => series.pointCount));\n\n let minX = hasExplicitMinX ? Number(chart.categoryAxis?.min) : Math.min(...allX);\n let maxX = hasExplicitMaxX ? Number(chart.categoryAxis?.max) : Math.max(...allX);\n let minY = hasExplicitMinY ? Number(chart.valueAxis?.min) : Math.min(...allY);\n let maxY = hasExplicitMaxY ? Number(chart.valueAxis?.max) : Math.max(...allY);\n\n if (!hasExplicitMinX) {\n minX = hasSyntheticIndexAxis\n ? 0\n : chart.categoryAxis?.crosses === \"autoZero\"\n ? Math.min(0, minX)\n : minX;\n }\n if (!hasExplicitMaxX) {\n maxX = hasSyntheticIndexAxis\n ? Math.max(maxX, syntheticPointCount + 1)\n : chart.categoryAxis?.crosses === \"autoZero\"\n ? Math.max(0, maxX)\n : maxX;\n }\n if (!hasExplicitMinY && chart.valueAxis?.crosses === \"autoZero\") {\n minY = Math.min(0, minY);\n }\n if (!hasExplicitMaxY && chart.valueAxis?.crosses === \"autoZero\") {\n maxY = Math.max(0, maxY);\n }\n\n if (maxX <= minX) {\n maxX = minX + 1;\n }\n if (maxY <= minY) {\n maxY = minY + 1;\n }\n\n const xStep = typeof chart.categoryAxis?.majorUnit === \"number\" && chart.categoryAxis.majorUnit > 0\n ? chart.categoryAxis.majorUnit\n : buildNiceStep(minX, maxX, 5);\n const yStep = typeof chart.valueAxis?.majorUnit === \"number\" && chart.valueAxis.majorUnit > 0\n ? chart.valueAxis.majorUnit\n : buildNiceStep(minY, maxY, 5);\n\n if (!hasExplicitMinX && !hasSyntheticIndexAxis && Number.isFinite(xStep) && xStep > 0) {\n minX = Math.floor(minX / xStep) * xStep;\n }\n if (!hasExplicitMaxX && !hasSyntheticIndexAxis && Number.isFinite(xStep) && xStep > 0) {\n maxX = Math.ceil(maxX / xStep) * xStep;\n }\n if (!hasExplicitMinY && Number.isFinite(yStep) && yStep > 0) {\n minY = Math.floor(minY / yStep) * yStep;\n }\n if (!hasExplicitMaxY && Number.isFinite(yStep) && yStep > 0) {\n maxY = Math.ceil(maxY / yStep) * yStep;\n }\n\n const safeMaxX = maxX <= minX ? minX + 1 : maxX;\n const safeMaxY = maxY <= minY ? minY + 1 : maxY;\n\n const xScale = scaleLinear().domain([minX, safeMaxX]).range([plot.left, plot.left + plot.width]);\n const yScale = scaleLinear().domain([minY, safeMaxY]).range([plot.top + plot.height, plot.top]);\n const xMajorUnit = typeof chart.categoryAxis?.majorUnit === \"number\" && chart.categoryAxis.majorUnit > 0\n ? chart.categoryAxis.majorUnit\n : hasSyntheticIndexAxis\n ? 1\n : undefined;\n const yMajorUnit = typeof chart.valueAxis?.majorUnit === \"number\" && chart.valueAxis.majorUnit > 0\n ? chart.valueAxis.majorUnit\n : buildNiceStep(minY, safeMaxY, 6);\n const xTicks = buildNumericTickValues(minX, safeMaxX, xMajorUnit);\n const yTicks = buildNumericTickValues(minY, safeMaxY, yMajorUnit);\n const axisColor = chart.axisLineColor ?? chart.chartAreaBorderColor ?? palette.border;\n const labelColor = resolveChartAxisTextColor(chart);\n\n const hasZeroX = minX <= 0 && safeMaxX >= 0;\n const hasZeroY = minY <= 0 && safeMaxY >= 0;\n\n return (\n <g>\n {xTicks.map((tick) => (\n <g key={`scatter-x-${tick}`}>\n <line\n stroke={lightenColor(axisColor, 0.7)}\n strokeWidth={1}\n x1={xScale(tick)}\n x2={xScale(tick)}\n y1={plot.top}\n y2={plot.top + plot.height}\n />\n <text fill={labelColor} fontSize={10} textAnchor=\"middle\" x={xScale(tick)} y={plot.top + plot.height + 14}>\n {formatTickValue(tick)}\n </text>\n </g>\n ))}\n {yTicks.map((tick) => (\n <g key={`scatter-y-${tick}`}>\n <line\n stroke={lightenColor(axisColor, 0.7)}\n strokeWidth={1}\n x1={plot.left}\n x2={plot.left + plot.width}\n y1={yScale(tick)}\n y2={yScale(tick)}\n />\n <text fill={labelColor} fontSize={10} textAnchor=\"end\" x={plot.left - 6} y={yScale(tick) + 3}>\n {formatTickValue(tick)}\n </text>\n </g>\n ))}\n {hasZeroY ? (\n <line\n stroke={axisColor}\n strokeWidth={1.2}\n x1={plot.left}\n x2={plot.left + plot.width}\n y1={yScale(0)}\n y2={yScale(0)}\n />\n ) : null}\n {hasZeroX ? (\n <line\n stroke={axisColor}\n strokeWidth={1.2}\n x1={xScale(0)}\n x2={xScale(0)}\n y1={plot.top}\n y2={plot.top + plot.height}\n />\n ) : null}\n {pointsBySeries.map((seriesPoints, seriesIndex) => {\n const series = seriesPoints.series;\n const markerSize = markerRadiusPx(series.markerSize);\n const markerPath = markerSymbolPath(\n normalizeChartMarkerSymbol(series.markerSymbol),\n markerSize\n );\n const markerFill = series.lineColor ?? series.markerColor ?? series.color ?? chartSeriesStrokeColor(chart, seriesIndex);\n const shouldDrawLine = styleDrawsLine\n && series.shapeProperties?.xmlLineHidden !== true\n && seriesPoints.points.length > 1;\n const shouldDrawMarkers = styleShowsMarkers\n && markerPath.length > 0;\n const lineCurve = smooth || styleUsesSmoothCurve || series.smooth === true\n ? curveCatmullRom.alpha(0.5)\n : curveLinear;\n const linePath = shouldDrawLine\n ? d3Line<{ x: number; y: number }>()\n .x((point) => xScale(point.x))\n .y((point) => yScale(point.y))\n .curve(lineCurve)(seriesPoints.points) ?? \"\"\n : \"\";\n\n return (\n <g key={`scatter-series-${seriesIndex}`}>\n {shouldDrawLine && linePath.length > 0 ? (\n <path\n {...chartElementDataProps(seriesIndex)}\n d={linePath}\n fill=\"none\"\n stroke={series.lineColor ?? chartSeriesStrokeColor(chart, seriesIndex)}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={Math.max(1.2, series.lineWidthPx ?? 2)}\n />\n ) : null}\n {seriesPoints.points.map((point, pointIndex) => {\n if (!shouldDrawMarkers) {\n return null;\n }\n return (\n <g\n key={`scatter-point-${seriesIndex}-${pointIndex}`}\n transform={`translate(${xScale(point.x)}, ${yScale(point.y)})`}\n >\n <path\n {...chartElementDataProps(seriesIndex, pointIndex, { selectionMode: \"seriesFirst\" })}\n d={markerPath}\n fill={markerFill}\n stroke=\"none\"\n strokeWidth={0}\n />\n </g>\n );\n })}\n {seriesPoints.points.map((point, pointIndex) => (\n isSelectedChartPoint(selectedChartElement, chart.id, seriesIndex, pointIndex)\n || (\n isSelectedChartSeries(selectedChartElement, chart.id, seriesIndex)\n && selectedChartElement?.kind !== \"point\"\n )\n ? renderSelectionPointHandles(\n `scatter-selection-${seriesIndex}-${pointIndex}`,\n [{ x: xScale(point.x), y: yScale(point.y) }]\n )\n : null\n ))}\n </g>\n );\n })}\n </g>\n );\n}\n\nfunction renderBubbleChart(chart: XlsxChart, palette: ChartRendererPalette, layout: ChartLayout, selectedChartElement?: XlsxChartElementSelection | null) {\n const plot = layout.plot;\n const pointsBySeries = chart.series.map((series) => (\n series.values.map((value, index) => {\n const x = safeNumber(series.categories[index]);\n const y = safeNumber(value);\n const bubble = safeNumber(series.bubbleSizes?.[index]);\n return x == null || y == null ? null : { bubble: bubble ?? 1, index, x, y };\n }).filter((point): point is { bubble: number; index: number; x: number; y: number } => point != null)\n ));\n\n const allX = pointsBySeries.flatMap((points) => points.map((point) => point.x));\n const allY = pointsBySeries.flatMap((points) => points.map((point) => point.y));\n const allBubble = pointsBySeries.flatMap((points) => points.map((point) => point.bubble));\n if (allX.length === 0 || allY.length === 0) {\n return null;\n }\n const minX = Math.min(...allX);\n const maxX = Math.max(...allX);\n const minY = Math.min(...allY);\n const maxY = Math.max(...allY);\n const bubbleMagnitudes = allBubble.map((value) => Math.sqrt(Math.max(0, value)));\n const minBubbleMagnitude = Math.min(...bubbleMagnitudes);\n const maxBubbleMagnitude = Math.max(...bubbleMagnitudes);\n\n const bubbleScaleFactor = clamp((chart.bubbleScale ?? 100) / 100, 0.2, 4);\n const minRadius = 4;\n const maxRadius = Math.max(minRadius + 2, 12 * bubbleScaleFactor);\n const radiusScale = scaleLinear()\n .domain([minBubbleMagnitude, maxBubbleMagnitude <= minBubbleMagnitude ? minBubbleMagnitude + 1 : maxBubbleMagnitude])\n .range([minRadius, maxRadius]);\n const safeMaxX = maxX <= minX ? minX + 1 : maxX;\n const safeMaxY = maxY <= minY ? minY + 1 : maxY;\n const xSpan = safeMaxX - minX;\n const ySpan = safeMaxY - minY;\n const xPad = Math.max(xSpan * 0.04, (xSpan * maxRadius) / Math.max(1, plot.width));\n const yPad = Math.max(ySpan * 0.06, (ySpan * maxRadius) / Math.max(1, plot.height));\n const xDomain = resolveAxisDomainWithChartOverrides(\n chart.categoryAxis,\n minX - xPad,\n safeMaxX + xPad,\n chart.categoryAxis?.crosses === \"autoZero\"\n );\n const yDomain = resolveAxisDomainWithChartOverrides(\n chart.valueAxis,\n minY - yPad,\n safeMaxY + yPad,\n chart.valueAxis?.crosses === \"autoZero\"\n );\n const xScale = scaleLinear().domain([xDomain.min, xDomain.max]).range([plot.left, plot.left + plot.width]);\n const yScale = scaleLinear().domain([yDomain.min, yDomain.max]).range([plot.top + plot.height, plot.top]);\n\n const xTicks = xDomain.ticks;\n const yTicks = yDomain.ticks;\n const axisColor = chart.axisLineColor ?? chart.chartAreaBorderColor ?? palette.border;\n const labelColor = resolveChartAxisTextColor(chart);\n const isBubble3d = chart.bubble3d === true || chart.is3d === true;\n const labelsEnabled = Boolean(\n chart.dataLabels?.showCategoryName\n || chart.dataLabels?.showSeriesName\n || chart.dataLabels?.showValue\n || chart.dataLabels?.showBubbleSize\n || chart.dataLabels?.showPercent\n );\n const bubbleTotals = pointsBySeries.map((points) => (\n points.reduce((sum, point) => sum + Math.abs(point.bubble), 0)\n ));\n\n return (\n <g>\n {xTicks.map((tick) => (\n <g key={`bubble-x-${tick}`}>\n <line\n stroke={lightenColor(axisColor, 0.72)}\n strokeWidth={1}\n x1={xScale(tick)}\n x2={xScale(tick)}\n y1={plot.top}\n y2={plot.top + plot.height}\n />\n <text fill={labelColor} fontSize={10} textAnchor=\"middle\" x={xScale(tick)} y={plot.top + plot.height + 14}>\n {formatTickValue(tick)}\n </text>\n </g>\n ))}\n {yTicks.map((tick) => (\n <g key={`bubble-y-${tick}`}>\n <line\n stroke={lightenColor(axisColor, 0.72)}\n strokeWidth={1}\n x1={plot.left}\n x2={plot.left + plot.width}\n y1={yScale(tick)}\n y2={yScale(tick)}\n />\n <text fill={labelColor} fontSize={10} textAnchor=\"end\" x={plot.left - 6} y={yScale(tick) + 3}>\n {formatTickValue(tick)}\n </text>\n </g>\n ))}\n <line stroke={axisColor} strokeWidth={1.2} x1={plot.left} x2={plot.left + plot.width} y1={plot.top + plot.height} y2={plot.top + plot.height} />\n <line stroke={axisColor} strokeWidth={1.2} x1={plot.left} x2={plot.left} y1={plot.top} y2={plot.top + plot.height} />\n {pointsBySeries.map((points, seriesIndex) => (\n <g key={`bubble-series-${seriesIndex}`}>\n {isBubble3d ? (\n <defs>\n <radialGradient id={`bubble3d-grad-${chart.id}-${seriesIndex}`} cx=\"35%\" cy=\"30%\" r=\"70%\">\n <stop offset=\"0%\" stopColor={lightenColor(chart.series[seriesIndex]?.color ?? chart.series[seriesIndex]?.lineColor ?? chartSeriesColor(chart, seriesIndex), 0.42)} />\n <stop offset=\"58%\" stopColor={chart.series[seriesIndex]?.color ?? chart.series[seriesIndex]?.lineColor ?? chartSeriesColor(chart, seriesIndex)} />\n <stop offset=\"100%\" stopColor={darkenColor(chart.series[seriesIndex]?.color ?? chart.series[seriesIndex]?.lineColor ?? chartSeriesColor(chart, seriesIndex), 0.18)} />\n </radialGradient>\n </defs>\n ) : null}\n {[...points]\n .sort((left, right) => {\n if (left.bubble !== right.bubble) {\n return right.bubble - left.bubble;\n }\n return left.index - right.index;\n })\n .map((point) => {\n const series = chart.series[seriesIndex];\n const baseColor = series?.color ?? series?.lineColor ?? chartSeriesColor(chart, seriesIndex);\n const radius = radiusScale(Math.sqrt(Math.max(0, point.bubble)));\n const pieces: string[] = [];\n if (chart.dataLabels?.showSeriesName && series?.name) {\n pieces.push(series.name);\n }\n if (chart.dataLabels?.showCategoryName) {\n pieces.push(formatTickValue(point.x));\n }\n if (chart.dataLabels?.showValue) {\n pieces.push(formatTickValue(point.y));\n }\n if (chart.dataLabels?.showBubbleSize) {\n pieces.push(formatTickValue(point.bubble));\n }\n if (chart.dataLabels?.showPercent) {\n pieces.push(`${Math.round((Math.abs(point.bubble) / Math.max(1, bubbleTotals[seriesIndex] ?? 1)) * 100)}%`);\n }\n return (\n <g key={`bubble-${seriesIndex}-${point.index}`}>\n <circle\n {...chartElementDataProps(seriesIndex, point.index, { selectionMode: \"seriesFirst\" })}\n cx={xScale(point.x)}\n cy={yScale(point.y)}\n fill={isBubble3d ? `url(#bubble3d-grad-${chart.id}-${seriesIndex})` : baseColor}\n fillOpacity={isBubble3d ? 0.98 : 0.78}\n r={radius}\n stroke={darkenColor(baseColor, 0.18)}\n strokeWidth={isBubble3d ? 1.2 : 1}\n />\n {isSelectedChartPoint(selectedChartElement, chart.id, seriesIndex, point.index)\n || (\n isSelectedChartSeries(selectedChartElement, chart.id, seriesIndex)\n && selectedChartElement?.kind !== \"point\"\n )\n ? renderSelectionRectHandles(\n `bubble-selection-${seriesIndex}-${point.index}`,\n xScale(point.x) - radius,\n yScale(point.y) - radius,\n radius * 2,\n radius * 2\n )\n : null}\n {isBubble3d ? (\n <ellipse\n cx={xScale(point.x) - radius * 0.16}\n cy={yScale(point.y) - radius * 0.22}\n fill=\"#ffffff\"\n opacity={0.22}\n rx={Math.max(1.5, radius * 0.34)}\n ry={Math.max(1, radius * 0.2)}\n />\n ) : null}\n {labelsEnabled && pieces.length > 0 ? (\n <text\n fill={resolveChartTextColor(chart)}\n fontSize={10}\n textAnchor=\"start\"\n x={xScale(point.x) + radius + 4}\n y={yScale(point.y) + 3}\n >\n {pieces.join(\", \")}\n </text>\n ) : null}\n </g>\n );\n })}\n </g>\n ))}\n </g>\n );\n}\n\nfunction renderRadarChart(chart: XlsxChart, palette: ChartRendererPalette, layout: ChartLayout, selectedChartElement?: XlsxChartElementSelection | null) {\n if (chart.series.length === 0) {\n return null;\n }\n const categories = getCategoryLabels(chart);\n if (categories.length === 0) {\n return null;\n }\n const plot = layout.plot;\n const centerX = plot.left + plot.width * 0.5;\n const centerY = plot.top + plot.height * 0.52;\n const radius = Math.max(22, Math.min(plot.width, plot.height) * 0.38);\n const values = chart.series.flatMap((series) => (\n series.values\n .slice(0, categories.length)\n .map((value) => safeNumber(value))\n .filter((value): value is number => value != null)\n ));\n const hasExplicitMin = typeof chart.valueAxis?.min === \"number\" && Number.isFinite(chart.valueAxis.min);\n const hasExplicitMax = typeof chart.valueAxis?.max === \"number\" && Number.isFinite(chart.valueAxis.max);\n let minValue = hasExplicitMin\n ? Number(chart.valueAxis?.min)\n : Math.min(0, ...(values.length ? values : [0]));\n let maxValue = hasExplicitMax\n ? Number(chart.valueAxis?.max)\n : Math.max(1, ...(values.length ? values : [1]));\n if (chart.valueAxis?.crosses === \"autoZero\") {\n minValue = Math.min(0, minValue);\n }\n const safeMax = maxValue <= minValue ? minValue + 1 : maxValue;\n const span = Math.max(1e-6, safeMax - minValue);\n const candidateMajorUnit = typeof chart.valueAxis?.majorUnit === \"number\" && chart.valueAxis.majorUnit > 0\n ? chart.valueAxis.majorUnit\n : undefined;\n const preferredMajorUnit = candidateMajorUnit && span / candidateMajorUnit >= 3\n ? candidateMajorUnit\n : buildNiceStep(minValue, safeMax, 6);\n const ticks = buildNumericTickValues(minValue, safeMax, preferredMajorUnit);\n const axisColor = chart.axisLineColor ?? chart.chartAreaBorderColor ?? palette.border;\n const labelColor = resolveChartAxisTextColor(chart);\n const filled = chart.radarStyle === \"filled\";\n const showSpokes = chart.categoryAxis?.majorGridlines === true;\n\n const angleAt = (index: number) => (Math.PI * 2 * index) / categories.length - Math.PI / 2;\n const radialPoint = (index: number, valueRatio: number) => {\n const angle = angleAt(index);\n const r = radius * valueRatio;\n return {\n x: centerX + Math.cos(angle) * r,\n y: centerY + Math.sin(angle) * r\n };\n };\n\n return (\n <g>\n {ticks.map((tick, ringIndex) => {\n const ratio = (tick - minValue) / (safeMax - minValue);\n const ringPoints = categories.map((_, categoryIndex) => radialPoint(categoryIndex, ratio));\n const ringPath = d3Line<{ x: number; y: number }>()\n .x((point) => point.x)\n .y((point) => point.y)\n .curve(curveLinearClosed)(ringPoints) ?? \"\";\n return (\n <g key={`radar-ring-${ringIndex}`}>\n <path\n d={ringPath}\n fill={ringIndex % 2 === 0 ? \"transparent\" : lightenColor(chart.chartAreaFillColor ?? palette.surface, 0.04)}\n stroke={lightenColor(axisColor, 0.5)}\n strokeWidth={1}\n />\n <text fill={labelColor} fontSize={9} x={centerX + 4} y={centerY - radius * ratio + 3}>\n {formatTickValue(tick)}\n </text>\n </g>\n );\n })}\n {categories.map((category, categoryIndex) => {\n const edge = radialPoint(categoryIndex, 1);\n return (\n <g key={`radar-axis-${categoryIndex}`}>\n {showSpokes ? (\n <line stroke={lightenColor(axisColor, 0.52)} strokeWidth={1} x1={centerX} x2={edge.x} y1={centerY} y2={edge.y} />\n ) : null}\n <text\n fill={labelColor}\n fontSize={10}\n textAnchor=\"middle\"\n x={centerX + (edge.x - centerX) * 1.1}\n y={centerY + (edge.y - centerY) * 1.1}\n >\n {category}\n </text>\n </g>\n );\n })}\n {chart.series.map((series, seriesIndex) => {\n const points = categories.map((_, categoryIndex) => {\n const rawValue = safeNumber(series.values[categoryIndex]);\n if (rawValue == null) {\n return {\n defined: false,\n pointIndex: categoryIndex,\n ...radialPoint(categoryIndex, 0)\n };\n }\n const ratio = clamp((rawValue - minValue) / (safeMax - minValue), 0, 1);\n return {\n defined: true,\n pointIndex: categoryIndex,\n ...radialPoint(categoryIndex, ratio)\n };\n });\n const definedPoints = points.filter((point) => point.defined);\n if (definedPoints.length === 0) {\n return null;\n }\n const hasGap = points.some((point) => !point.defined);\n const polygon = d3Line<{ defined: boolean; x: number; y: number }>()\n .defined((point) => point.defined)\n .x((point) => point.x)\n .y((point) => point.y)\n .curve(hasGap ? curveLinear : curveLinearClosed)(points) ?? \"\";\n const color = chartSeriesColor(chart, seriesIndex);\n const markerSymbol = normalizeChartMarkerSymbol(series.markerSymbol);\n const markerSize = markerRadiusPx(series.markerSize);\n const markerPath = markerSymbolPath(markerSymbol, markerSize);\n\t const showMarkers = markerSymbol !== \"none\" && markerPath.length > 0;\n\t return (\n\t <g key={`radar-series-${seriesIndex}`}>\n\t {definedPoints.length >= 2 ? (\n\t <path\n\t {...chartElementDataProps(seriesIndex)}\n\t d={polygon}\n\t fill={filled && !hasGap && definedPoints.length >= 3 ? color : \"none\"}\n\t fillOpacity={filled ? 0.26 : 0}\n\t stroke={chartSeriesStrokeColor(chart, seriesIndex)}\n\t strokeWidth={1.8}\n\t />\n\t ) : null}\n\t {showMarkers\n\t ? definedPoints.map((point) => (\n\t <g\n\t key={`radar-point-${seriesIndex}-${point.pointIndex}`}\n\t transform={`translate(${point.x}, ${point.y})`}\n\t >\n\t <path\n\t {...chartElementDataProps(seriesIndex, point.pointIndex)}\n\t d={markerPath}\n\t fill={series.markerColor ?? color}\n\t stroke={series.markerLineColor ?? chart.chartAreaFillColor ?? palette.surface}\n\t strokeWidth={1}\n\t />\n\t </g>\n\t ))\n\t : null}\n\t {definedPoints.map((point) => (\n\t isSelectedChartPoint(selectedChartElement, chart.id, seriesIndex, point.pointIndex)\n\t || (\n\t isSelectedChartSeries(selectedChartElement, chart.id, seriesIndex)\n\t && selectedChartElement?.kind !== \"point\"\n\t )\n\t ? renderSelectionPointHandles(\n\t `radar-selection-${seriesIndex}-${point.pointIndex}`,\n\t [{ x: point.x, y: point.y }]\n\t )\n\t : null\n\t ))}\n\t </g>\n\t );\n })}\n </g>\n );\n}\n\nfunction renderPieChart(chart: XlsxChart, palette: ChartRendererPalette, layout: ChartLayout, chartType: string, selectedChartElement?: XlsxChartElementSelection | null) {\n const pieSeriesIndex = selectPrimaryPieSeriesIndex(chart);\n const pieSeries = chart.series[pieSeriesIndex];\n const pieData = buildPieEntries(chart, pieSeriesIndex);\n if (pieData.length === 0) {\n return null;\n }\n\n const legendOnRight = layout.legendPosition === \"right\";\n const centerX = legendOnRight ? layout.plot.left + layout.plot.width * 0.42 : layout.plot.left + layout.plot.width * 0.5;\n const centerY = layout.plot.top + layout.plot.height * 0.54;\n const outerRadius = Math.max(16, Math.min(layout.plot.width, layout.plot.height) * (chartType === \"Doughnut\" ? 0.32 : 0.38));\n const innerRatio = chartType === \"Doughnut\" ? clamp((chart.holeSize ?? 56) / 100, 0.1, 0.9) : 0;\n const innerRadius = outerRadius * innerRatio;\n const startAngle = ((chart.firstSliceAngle ?? 0) * Math.PI) / 180;\n const arcs = d3Pie<{ color: string; index: number; label: string; value: number }>()\n .value((entry) => entry.value)\n .sort(null)\n .startAngle(startAngle)\n .endAngle(startAngle + Math.PI * 2)(pieData);\n\n const arcPath = d3Arc<typeof arcs[number]>()\n .innerRadius(innerRadius)\n .outerRadius(outerRadius);\n\n const isPie3d = chartType === \"Pie3D\" || (chartType === \"PieExploded\" && chart.is3d === true);\n const rotX = chart.view3d?.rotX ?? 20;\n const perspective = chart.view3d?.perspective ?? 30;\n const tiltFromRotX = clamp(0.14 + (rotX / 90) * 0.72, 0.12, 0.92);\n const perspectiveCompression = clamp(1 - (perspective / 180), 0.55, 1);\n const tilt = isPie3d ? clamp(tiltFromRotX * perspectiveCompression, 0.14, 0.78) : 1;\n const depthScale = (chart.view3d?.depthPercent ?? 100) / 100;\n const depth = isPie3d ? Math.max(9, outerRadius * 0.28 * depthScale) : 0;\n const dataLabelsEnabled = Boolean(chart.dataLabels?.showCategoryName || chart.dataLabels?.showPercent || chart.dataLabels?.showValue);\n const total = pieData.reduce((sum, entry) => sum + entry.value, 0);\n const shadowId = `pie3d-shadow-${chart.id}`.replace(/[^A-Za-z0-9_-]/g, \"-\");\n const baseShadowId = `pie3d-base-shadow-${chart.id}`.replace(/[^A-Za-z0-9_-]/g, \"-\");\n const sliceSeparatorColor = chart.chartAreaFillColor ?? \"#ffffff\";\n const labelBounds = {\n bottom: layout.height - 6,\n left: 6,\n right: layout.width - 6,\n top: layout.plot.top + 8\n };\n const pointLabelByIndex = new Map((chart.dataLabels?.pointLabels ?? []).map((label) => [label.index, label]));\n const centerValuePointLabel = chartType === \"Doughnut\"\n ? (chart.dataLabels?.pointLabels ?? []).find((label) => (\n label.deleted !== true\n && label.showValue === true\n && label.showCategoryName !== true\n && label.showPercent !== true\n && label.showSeriesName !== true\n && label.showBubbleSize !== true\n )) ?? null\n : null;\n const centerValueEntry = centerValuePointLabel\n ? pieData.find((entry) => entry.index === centerValuePointLabel.index) ?? null\n : null;\n const shouldRenderCenterValue = chartType === \"Doughnut\" && centerValueEntry != null;\n const centerValueLooksPercent = centerValueEntry != null\n && total > 0\n && total <= 1.0000001\n && centerValueEntry.value >= 0\n && centerValueEntry.value <= 1.0000001;\n const centerValueText = centerValueEntry == null\n ? \"\"\n : centerValueLooksPercent\n ? `${Math.round(centerValueEntry.value * 100)}%`\n : formatTickValue(centerValueEntry.value);\n const centerValueFontSize = shouldRenderCenterValue\n ? Math.max(\n 14,\n Math.min(\n Math.max(20, innerRadius * 0.72),\n (centerValuePointLabel?.fontSizePt ?? 28) * 0.85\n )\n )\n : 0;\n\n const resolveSliceExplosion = (pointIndex: number) => {\n const pointStyle = pieSeries?.dataPointStyles?.find((entry) => entry.index === pointIndex);\n const seriesExplosion = typeof pieSeries?.shapeProperties?.xmlExplosion === \"number\"\n ? pieSeries.shapeProperties.xmlExplosion\n : 0;\n const rawExplosion = Math.max(0, pointStyle?.explosion ?? seriesExplosion ?? 0);\n if (rawExplosion <= 0) {\n return 0;\n }\n // OOXML explosion values are percent-like offsets of the pie radius.\n return outerRadius * clamp(rawExplosion / 100, 0, 4);\n };\n const hasExplodedSlices = arcs.some((arc) => resolveSliceExplosion(arc.data.index) > 0);\n const sliceSeparatorWidth = hasExplodedSlices ? 2 : 1.2;\n\n return (\n <g>\n {isPie3d ? (\n <defs>\n <filter id={shadowId} x=\"-40%\" y=\"-40%\" width=\"180%\" height=\"200%\">\n <feDropShadow dx=\"1.2\" dy=\"3.6\" floodColor=\"#000000\" floodOpacity=\"0.28\" stdDeviation=\"2.8\" />\n </filter>\n <filter id={baseShadowId} x=\"-50%\" y=\"-50%\" width=\"220%\" height=\"220%\">\n <feGaussianBlur stdDeviation=\"3.2\" />\n </filter>\n </defs>\n ) : null}\n {isPie3d ? (\n <ellipse\n cx={centerX}\n cy={centerY + depth + 3}\n fill=\"#000000\"\n filter={`url(#${baseShadowId})`}\n opacity={0.14}\n rx={outerRadius * 1.02}\n ry={outerRadius * tilt * 0.68}\n />\n ) : null}\n {isPie3d\n ? arcs.map((arc) => {\n const midAngle = (arc.startAngle + arc.endAngle) / 2;\n const explosion = resolveSliceExplosion(arc.data.index);\n const explodeX = Math.sin(midAngle) * explosion;\n const explodeY = -Math.cos(midAngle) * explosion * tilt;\n const sidePaths = buildPieOuterWallPath(\n centerX,\n centerY,\n outerRadius,\n tilt,\n depth,\n arc.startAngle,\n arc.endAngle,\n explosion > 0\n );\n if (sidePaths.length === 0) {\n return null;\n }\n return (\n <g key={`pie-side-${arc.data.index}`} transform={`translate(${explodeX}, ${explodeY})`}>\n {sidePaths.map((sidePath, sideIndex) => (\n <path\n d={sidePath}\n fill={darkenColor(arc.data.color, 0.34)}\n key={`pie-side-path-${arc.data.index}-${sideIndex}`}\n stroke={darkenColor(arc.data.color, 0.5)}\n strokeWidth={0.8}\n />\n ))}\n {explosion > 0 ? (() => {\n const startWall = buildPieRadialWallPath(\n centerX,\n centerY,\n outerRadius,\n tilt,\n depth,\n arc.startAngle,\n true\n );\n const endWall = buildPieRadialWallPath(\n centerX,\n centerY,\n outerRadius,\n tilt,\n depth,\n arc.endAngle,\n true\n );\n return (\n <>\n {startWall ? (\n <path\n d={startWall}\n fill={darkenColor(arc.data.color, 0.26)}\n stroke={darkenColor(arc.data.color, 0.44)}\n strokeWidth={0.8}\n />\n ) : null}\n {endWall ? (\n <path\n d={endWall}\n fill={darkenColor(arc.data.color, 0.2)}\n stroke={darkenColor(arc.data.color, 0.4)}\n strokeWidth={0.8}\n />\n ) : null}\n </>\n );\n })() : null}\n </g>\n );\n })\n : null}\n {arcs.map((arc) => {\n const explosion = resolveSliceExplosion(arc.data.index);\n const midAngle = (arc.startAngle + arc.endAngle) / 2;\n const explodeX = Math.sin(midAngle) * explosion;\n const explodeY = -Math.cos(midAngle) * explosion * (isPie3d ? tilt : 1);\n const isSliceSelected = isSelectedChartPoint(selectedChartElement, chart.id, pieSeriesIndex, arc.data.index)\n || (\n isSelectedChartSeries(selectedChartElement, chart.id, pieSeriesIndex)\n && selectedChartElement?.kind !== \"point\"\n );\n const sliceHandlePoints = isSliceSelected\n ? [\n pieEllipsePoint(centerX, centerY, outerRadius, isPie3d ? tilt : 1, arc.startAngle),\n pieEllipsePoint(centerX, centerY, outerRadius, isPie3d ? tilt : 1, midAngle),\n pieEllipsePoint(centerX, centerY, outerRadius, isPie3d ? tilt : 1, arc.endAngle),\n innerRadius > 0\n ? pieEllipsePoint(centerX, centerY, innerRadius, isPie3d ? tilt : 1, midAngle)\n : { x: centerX, y: centerY }\n ].map((point) => ({\n x: point.x + explodeX,\n y: point.y + explodeY\n }))\n : [];\n const labelRadius = outerRadius + (chartType === \"PieExploded\" ? 8 : 12);\n const labelX = centerX + Math.sin(midAngle) * labelRadius + explodeX;\n const labelY = centerY - Math.cos(midAngle) * labelRadius * (isPie3d ? tilt : 1) + explodeY;\n const pieces: string[] = [];\n if (chart.dataLabels?.showCategoryName && arc.data.label.trim().length > 0) {\n pieces.push(arc.data.label);\n }\n const pointLabel = pointLabelByIndex.get(arc.data.index);\n const showValue = pointLabel?.showValue ?? chart.dataLabels?.showValue;\n const showPercent = pointLabel?.showPercent ?? chart.dataLabels?.showPercent;\n if (showValue) {\n pieces.push(formatTickValue(arc.data.value));\n }\n if (showPercent) {\n pieces.push(`${Math.round((arc.data.value / Math.max(1, total)) * 100)}%`);\n }\n const labelText = pieces.join(\", \");\n const truncatedLabelText = truncateSvgText(labelText, Math.max(48, layout.width * 0.42), 10);\n const approxLabelWidth = Math.max(12, truncatedLabelText.length * 5.6);\n let labelAnchor: \"end\" | \"start\" = labelX >= centerX ? \"start\" : \"end\";\n let resolvedLabelX = labelX;\n if (labelAnchor === \"start\" && resolvedLabelX + approxLabelWidth > labelBounds.right) {\n labelAnchor = \"end\";\n }\n if (labelAnchor === \"end\" && resolvedLabelX - approxLabelWidth < labelBounds.left) {\n labelAnchor = \"start\";\n }\n resolvedLabelX = clamp(resolvedLabelX, labelBounds.left, labelBounds.right);\n const resolvedLabelY = clamp(labelY, labelBounds.top, labelBounds.bottom);\n return (\n <React.Fragment key={`pie-top-${arc.data.index}`}>\n <g transform={`translate(${explodeX}, ${explodeY})`}>\n <path\n {...chartElementDataProps(pieSeriesIndex, arc.data.index)}\n d={(arcPath(arc) ?? \"\")}\n fill={arc.data.color}\n filter={isPie3d ? `url(#${shadowId})` : undefined}\n stroke={isSliceSelected ? \"#64748b\" : sliceSeparatorColor}\n strokeWidth={isSliceSelected ? Math.max(2, sliceSeparatorWidth) : sliceSeparatorWidth}\n transform={`translate(${centerX}, ${centerY})${isPie3d ? ` scale(1, ${tilt})` : \"\"}`}\n />\n </g>\n {isSliceSelected\n ? renderSelectionPointHandles(`pie-selection-${arc.data.index}`, sliceHandlePoints)\n : null}\n {dataLabelsEnabled && truncatedLabelText.length > 0 ? (\n <text\n fill={resolveChartTextColor(chart)}\n fontSize={10}\n textAnchor={labelAnchor}\n x={resolvedLabelX}\n y={resolvedLabelY}\n >\n {truncatedLabelText}\n </text>\n ) : null}\n </React.Fragment>\n );\n })}\n {shouldRenderCenterValue ? (\n <text\n fill={chart.textColor ?? chart.titleColor ?? DEFAULT_CHART_TEXT_COLOR}\n fontSize={centerValueFontSize}\n fontWeight={700}\n textAnchor=\"middle\"\n x={centerX}\n y={centerY + centerValueFontSize * 0.34}\n >\n {centerValueText}\n </text>\n ) : null}\n </g>\n );\n}\n\nfunction renderBarOfPieChart(chart: XlsxChart, palette: ChartRendererPalette, layout: ChartLayout, selectedChartElement?: XlsxChartElementSelection | null) {\n const pieSeriesIndex = selectPrimaryPieSeriesIndex(chart);\n const pieSeries = chart.series[pieSeriesIndex];\n const categories = getCategoryLabels(chart);\n const values = pieSeries?.values.map((value) => Math.max(0, safeNumber(value) ?? 0)) ?? [];\n if (values.length === 0) {\n return null;\n }\n const raw = (chart.raw ?? {}) as Record<string, unknown>;\n const ofPieType = raw.ofPieType === \"pie\" ? \"pie\" : \"bar\";\n const splitPos = typeof raw.splitPos === \"number\" ? raw.splitPos : 0;\n let secondaryIndices = values\n .map((value, index) => ({ index, value }))\n .filter(({ value }) => value <= splitPos)\n .map(({ index }) => index);\n if (secondaryIndices.length === 0) {\n secondaryIndices = values\n .map((value, index) => ({ index, value }))\n .sort((left, right) => left.value - right.value)\n .slice(0, Math.min(2, values.length))\n .map(({ index }) => index);\n }\n const secondarySet = new Set(secondaryIndices);\n const secondaryTotal = secondaryIndices.reduce((sum, index) => sum + (values[index] ?? 0), 0);\n const primaryData = values.flatMap((value, index) => secondarySet.has(index)\n ? []\n : [{ color: chartPointColor(chart, index, pieSeriesIndex), index, label: categories[index], value }]);\n if (secondaryTotal > 0) {\n primaryData.push({\n color: chartPointColor(chart, secondaryIndices[0] ?? 0, pieSeriesIndex),\n index: secondaryIndices[0] ?? 0,\n label: \"Other\",\n value: secondaryTotal\n });\n }\n\n const pieCenterX = layout.plot.left + layout.plot.width * 0.28;\n const pieCenterY = layout.plot.top + layout.plot.height * 0.55;\n const pieRadius = Math.max(16, Math.min(layout.plot.height, layout.plot.width * 0.45) * 0.3);\n const arc = d3Arc<{ endAngle: number; startAngle: number }>().innerRadius(0).outerRadius(pieRadius);\n const pieArcs = d3Pie<{ color: string; index: number; label: string; value: number }>()\n .value((entry) => entry.value)\n .sort(null)\n .startAngle(((90 - (chart.firstSliceAngle ?? 0)) * Math.PI) / 180)\n .endAngle(((90 - (chart.firstSliceAngle ?? 0)) * Math.PI) / 180 + Math.PI * 2)(primaryData);\n\n const secondaryLabels = secondaryIndices.map((index) => categories[index] ?? \"\");\n const secondaryValues = secondaryIndices.map((index) => values[index] ?? 0);\n const connectorTargetX = layout.plot.left + layout.plot.width * 0.69;\n const secondaryData = secondaryIndices.map((index) => ({\n color: chartPointColor(chart, index, pieSeriesIndex),\n index,\n label: categories[index] ?? \"\",\n value: values[index] ?? 0\n }));\n const secondaryCenterX = layout.plot.left + layout.plot.width * 0.79;\n const secondaryCenterY = pieCenterY;\n const secondaryRadius = pieRadius * clamp(((typeof raw.secondPieSize === \"number\" ? raw.secondPieSize : 100) / 100), 0.55, 1.5);\n const secondaryArc = d3Arc<{ endAngle: number; startAngle: number }>().innerRadius(0).outerRadius(secondaryRadius);\n const secondaryPieArcs = d3Pie<{ color: string; index: number; label: string; value: number }>()\n .value((entry) => entry.value)\n .sort(null)\n .startAngle(((90 - (chart.firstSliceAngle ?? 0)) * Math.PI) / 180)\n .endAngle(((90 - (chart.firstSliceAngle ?? 0)) * Math.PI) / 180 + Math.PI * 2)(secondaryData);\n const stackedBarLeft = layout.plot.left + layout.plot.width * 0.72;\n const stackedBarWidth = Math.max(20, layout.plot.width * 0.13);\n const stackedBarTop = layout.plot.top + 16;\n const stackedBarHeight = Math.max(28, layout.plot.height - 32);\n const secondaryTotalSafe = Math.max(1e-6, secondaryTotal);\n let stackCursor = stackedBarTop;\n\n return (\n <g>\n {pieArcs.map((entry, index) => {\n const selected = isSelectedChartPointOrSeries(selectedChartElement, chart.id, pieSeriesIndex, entry.data.index);\n const midAngle = (entry.startAngle + entry.endAngle) / 2;\n const dot = pieEllipsePoint(pieCenterX, pieCenterY, pieRadius * 0.62, 1, midAngle);\n return (\n <React.Fragment key={`bar-of-pie-main-${index}`}>\n <path\n {...chartElementDataProps(pieSeriesIndex, entry.data.index)}\n d={arc(entry) ?? \"\"}\n fill={entry.data.color}\n stroke={selected ? \"#64748b\" : chart.chartAreaFillColor ?? palette.surface}\n strokeWidth={selected ? 2 : 1}\n transform={`translate(${pieCenterX}, ${pieCenterY})`}\n />\n {selected\n ? renderSelectionPointHandles(`bar-of-pie-main-selection-${index}`, [dot])\n : null}\n </React.Fragment>\n );\n })}\n <line\n stroke={chart.chartAreaBorderColor ?? palette.border}\n strokeWidth={1}\n x1={pieCenterX + pieRadius}\n x2={connectorTargetX}\n y1={pieCenterY - pieRadius * 0.4}\n y2={layout.plot.top + 10}\n />\n <line\n stroke={chart.chartAreaBorderColor ?? palette.border}\n strokeWidth={1}\n x1={pieCenterX + pieRadius}\n x2={connectorTargetX}\n y1={pieCenterY + pieRadius * 0.4}\n y2={layout.plot.top + layout.plot.height - 10}\n />\n {ofPieType === \"pie\"\n ? secondaryPieArcs.map((entry, index) => {\n const selected = isSelectedChartPointOrSeries(selectedChartElement, chart.id, pieSeriesIndex, entry.data.index);\n const midAngle = (entry.startAngle + entry.endAngle) / 2;\n const dot = pieEllipsePoint(secondaryCenterX, secondaryCenterY, secondaryRadius * 0.62, 1, midAngle);\n return (\n <React.Fragment key={`bar-of-pie-secondary-pie-${index}`}>\n <path\n {...chartElementDataProps(pieSeriesIndex, entry.data.index)}\n d={secondaryArc(entry) ?? \"\"}\n fill={entry.data.color}\n stroke={selected ? \"#64748b\" : chart.chartAreaFillColor ?? palette.surface}\n strokeWidth={selected ? 2 : 1}\n transform={`translate(${secondaryCenterX}, ${secondaryCenterY})`}\n />\n {selected\n ? renderSelectionPointHandles(`bar-of-pie-secondary-pie-selection-${index}`, [dot])\n : null}\n </React.Fragment>\n );\n })\n : secondaryData.map((entry, index) => {\n const segmentHeight = index === secondaryData.length - 1\n ? Math.max(1, stackedBarTop + stackedBarHeight - stackCursor)\n : Math.max(1, (entry.value / secondaryTotalSafe) * stackedBarHeight);\n const y = stackCursor;\n stackCursor += segmentHeight;\n const selected = isSelectedChartPointOrSeries(selectedChartElement, chart.id, pieSeriesIndex, entry.index);\n return (\n <g key={`bar-of-pie-secondary-bar-${index}`}>\n <rect\n {...chartElementDataProps(pieSeriesIndex, entry.index)}\n fill={entry.color}\n height={segmentHeight}\n stroke={selected ? \"#64748b\" : chart.chartAreaFillColor ?? palette.surface}\n strokeWidth={selected ? 2 : 1}\n width={stackedBarWidth}\n x={stackedBarLeft}\n y={y}\n />\n {selected\n ? renderSelectionRectHandles(\n `bar-of-pie-secondary-bar-selection-${index}`,\n stackedBarLeft,\n y,\n stackedBarWidth,\n segmentHeight\n )\n : null}\n <text\n fill={resolveChartAxisTextColor(chart)}\n fontSize={10}\n textAnchor=\"start\"\n x={stackedBarLeft + stackedBarWidth + 6}\n y={y + segmentHeight * 0.5 + 3}\n >\n {entry.label}\n </text>\n </g>\n );\n })}\n </g>\n );\n}\n\nfunction renderSurfaceChart(chart: XlsxChart, palette: ChartRendererPalette, layout: ChartLayout, selectedChartElement?: XlsxChartElementSelection | null) {\n const plot = resolveSurfacePlotRect(chart, layout);\n const categories = getCategoryLabels(chart);\n const rows = chart.series.length;\n const cols = Math.max(\n categories.length,\n chart.series.reduce((max, series) => Math.max(max, series.values.length), 0)\n );\n if (rows === 0 || cols === 0) {\n return null;\n }\n const matrix = chart.series.map((series) => (\n Array.from({ length: cols }, (_, columnIndex) => safeNumber(series.values[columnIndex]))\n ));\n const domain = getSurfaceDomain(chart);\n if (!domain) {\n return null;\n }\n const isContour = isContourSurfaceChart(chart);\n const ratios = surfaceDataRatios(rows, cols, chart.valueAxis?.crossBetween !== \"midCat\", chart.view3d?.heightPercent, chart.view3d?.depthPercent, layout);\n const minValue = domain.minValue;\n const safeMax = domain.safeMax;\n const wallFill = chart.backWall?.fillColor ?? \"#d9d9df\";\n const wallLineColor = chart.backWall?.lineColor ?? chart.sideWall?.lineColor ?? chart.floor?.lineColor ?? (chart.axisLineColor ?? lightenColor(resolveSurfaceBaseColor(chart, palette), 0.4));\n\n if (isContour) {\n const faces: React.ReactNode[] = [];\n const lines: React.ReactNode[] = [];\n const backgroundNormal = transformSurfaceNormal({ x: 0, y: 1, z: 0 }, chart.view3d?.rotX ?? 90, chart.view3d?.rotY ?? 0);\n const backgroundFill = chart.surfaceMaterial === \"flat\" ? wallFill : shadeSurfaceMatteColor(wallFill, backgroundNormal);\n const inset = chart.valueAxis?.crossBetween !== \"midCat\" ? plot.width / (2 * cols) : 0;\n const dataWidth = plot.width - 2 * inset;\n for (let rowIndex = 0; rowIndex < rows - 1; rowIndex += 1) {\n for (let columnIndex = 0; columnIndex < cols - 1; columnIndex += 1) {\n const p00 = matrix[rowIndex]?.[columnIndex];\n const p10 = matrix[rowIndex]?.[columnIndex + 1];\n const p01 = matrix[rowIndex + 1]?.[columnIndex];\n const p11 = matrix[rowIndex + 1]?.[columnIndex + 1];\n if (p00 == null || p10 == null || p01 == null || p11 == null) {\n continue;\n }\n const x0 = plot.left + inset + columnIndex / (cols - 1) * dataWidth;\n const x1 = plot.left + inset + (columnIndex + 1) / (cols - 1) * dataWidth;\n const y0 = plot.top + plot.height - rowIndex / (rows - 1) * plot.height;\n const y1 = plot.top + plot.height - (rowIndex + 1) / (rows - 1) * plot.height;\n const triangles = triangulateSurfaceQuad([\n { value: p00, x: x0, y: y0 },\n { value: p10, x: x1, y: y0 },\n { value: p11, x: x1, y: y1 },\n { value: p01, x: x0, y: y1 }\n ], chart.valueAxis);\n triangles.forEach((triangle, triangleIndex) => {\n const world = triangle.map(point => ({\n x: (point.x - plot.left - inset) / dataWidth,\n y: (1 - normalizeSurfaceValue(point.value, domain.minValue, domain.safeMax, chart.valueAxis)) * ratios.height,\n z: (point.y - plot.top) / plot.height * ratios.depth\n }));\n const normal = transformSurfaceNormal(surfaceNormal(world[0], world[1], world[2]), chart.view3d?.rotX ?? 90, chart.view3d?.rotY ?? 0);\n for (let band = 0; band < domain.ticks.length - 1; band += 1) {\n const lower = domain.ticks[band];\n const upper = domain.ticks[band + 1];\n const polygon = clipSurfaceBand(clipSurfaceBand(triangle, lower, true, chart.valueAxis, band === 0), upper, false, chart.valueAxis);\n if (polygon.length < 3) {\n continue;\n }\n const key = `${rowIndex}-${columnIndex}-${triangleIndex}-${band}`;\n const midpoint = (lower + upper) / 2;\n if (!chart.wireframe) {\n faces.push(<polygon key={`surface-band-${key}`} fill={chart.surfaceMaterial === \"flat\" ? resolveSurfaceBandColor(chart, palette, domain, midpoint) : shadeSurfaceMatteColor(resolveSurfaceBandColor(chart, palette, domain, midpoint), normal)} points={polygon.map((point) => `${point.x},${point.y}`).join(\" \")} />);\n }\n const widths = chart.raw?.bandFormatLineWidths as Record<string, number> | undefined;\n const lineWidth = widths?.[band] ?? chart.series[0]?.lineWidthPx ?? 1;\n const edges = surfaceBandEdges(polygon, triangle);\n lines.push(\n <path\n key={`surface-edge-${key}`}\n d={edges.map(([from, to]) => `M ${from.x} ${from.y} L ${to.x} ${to.y}`).join(\" \")}\n fill=\"none\"\n stroke={resolveSurfaceWireframeColor(chart, palette, domain, midpoint)}\n strokeWidth={lineWidth}\n />\n );\n }\n });\n }\n }\n return (\n <g>\n <rect\n fill={chart.raw?.plotAreaNoFill === true ? \"transparent\" : typeof chart.raw?.plotAreaFillColor === \"string\" ? chart.raw.plotAreaFillColor : backgroundFill}\n x={layout.plot.left}\n y={layout.plot.top}\n width={layout.plot.width}\n height={layout.plot.height}\n stroke={typeof chart.raw?.plotAreaLineColor === \"string\" ? chart.raw.plotAreaLineColor : wallLineColor}\n />\n <rect fill=\"none\" height={plot.height} stroke={wallLineColor} width={plot.width} x={plot.left} y={plot.top} />\n {faces}\n {lines}\n </g>\n );\n }\n\n const rotX = (chart.view3d?.rotX ?? 25) * (Math.PI / 180);\n const rotY = (chart.view3d?.rotY ?? 30) * (Math.PI / 180);\n const usePerspective = chart.view3d?.rAngAx === false;\n const perspectiveStrength = clamp(\n (chart.view3d?.perspective ?? (usePerspective ? 30 : 0)) / 100,\n 0,\n 1\n );\n const depthScale = ratios.depth;\n const heightExtent = 2 * ratios.height;\n const cosX = Math.cos(rotX);\n const sinX = Math.sin(rotX);\n const cosY = Math.cos(rotY);\n const sinY = Math.sin(rotY);\n\n type SurfacePoint = { depth: number; hasValue: boolean; value: number; x: number; y: number };\n const projectRawPoint = (columnIndex: number, rowIndex: number, value: number | null): SurfacePoint => {\n const hasValue = value != null;\n const normalizedX = cols <= 1 ? 0 : ((columnIndex / (cols - 1)) - 0.5) * 2;\n const normalizedY = hasValue ? -(normalizeSurfaceValue(value, minValue, safeMax, chart.valueAxis) - 0.5) * heightExtent : heightExtent / 2;\n const normalizedZ = rows <= 1 ? 0 : ((rowIndex / (rows - 1)) - 0.5) * 2 * depthScale;\n if (chart.view3d?.rAngAx !== false) {\n return {\n depth: normalizedZ,\n hasValue,\n value: value ?? minValue,\n x: normalizedX + normalizedZ * sinY,\n y: normalizedY - normalizedZ * sinX\n };\n }\n const x1 = normalizedX * cosY + normalizedZ * sinY;\n const z1 = -normalizedX * sinY + normalizedZ * cosY;\n const y1 = normalizedY * cosX - z1 * sinX;\n const z2 = normalizedY * sinX + z1 * cosX;\n const perspective = usePerspective ? 1 / Math.max(0.18, 1 + z2 * (0.24 + perspectiveStrength * 0.5)) : 1;\n return { depth: z2, hasValue, value: value ?? minValue, x: x1 * perspective, y: y1 * perspective };\n };\n const rawPoints = matrix.map((row, rowIndex) => row.map((value, columnIndex) => projectRawPoint(columnIndex, rowIndex, value)));\n\n const bounds = [\n ...rawPoints.flat(),\n ...[0, cols - 1].flatMap(column => [0, rows - 1].flatMap(row => [minValue, safeMax].map(value => projectRawPoint(column, row, value))))\n ];\n const minX = Math.min(...bounds.map((point) => point.x));\n const maxX = Math.max(...bounds.map((point) => point.x));\n const minY = Math.min(...bounds.map((point) => point.y));\n const maxY = Math.max(...bounds.map((point) => point.y));\n const scale = Math.min(\n layout.plot.width / Math.max(0.25, maxX - minX),\n layout.plot.height / Math.max(0.25, maxY - minY)\n );\n const centerX = layout.plot.left + layout.plot.width / 2;\n const centerY = layout.plot.top + layout.plot.height / 2;\n const centerRawX = (minX + maxX) / 2;\n const centerRawY = (minY + maxY) / 2;\n\n const projectPoint = (point: {x: number; y: number; value: number}) => {\n const projected = projectRawPoint(point.x, point.y, point.value);\n return { ...projected, x: centerX + (projected.x - centerRawX) * scale, y: centerY + (projected.y - centerRawY) * scale };\n };\n const wallNodes: React.ReactNode[] = [];\n const backRow = chart.view3d?.rAngAx !== false || cosX * cosY >= 0 ? rows - 1 : 0;\n const sideColumn = sinY >= 0 ? 0 : cols - 1;\n const wallPoint = (x: number, y: number, value: number) => ({ x, y, value });\n const addWall = (key: string, points: Array<{ x: number; y: number; value: number }>, color: string | undefined, hidden: boolean | undefined) => {\n if (hidden || color === \"transparent\") return;\n const world = points.map(point => ({\n x: point.x / Math.max(1, cols - 1),\n y: (1 - normalizeSurfaceValue(point.value, minValue, safeMax, chart.valueAxis)) * ratios.height,\n z: (1 - point.y / Math.max(1, rows - 1)) * depthScale\n }));\n const normal = transformSurfaceNormal(surfaceNormal(world[0], world[1], world[2]), chart.view3d?.rotX ?? 25, chart.view3d?.rotY ?? 30, chart.view3d?.rAngAx !== false);\n const baseColor = color ?? wallFill;\n wallNodes.push(<polygon key={key} fill={chart.surfaceMaterial === \"flat\" ? baseColor : shadeSurfaceMatteColor(baseColor, normal)} points={points.map(projectPoint).map(point => `${point.x},${point.y}`).join(\" \")} />);\n };\n addWall(\"floor\", [wallPoint(0, 0, minValue), wallPoint(cols - 1, 0, minValue), wallPoint(cols - 1, rows - 1, minValue), wallPoint(0, rows - 1, minValue)], chart.floor?.fillColor, chart.floor?.hidden);\n addWall(\"back\", [wallPoint(0, backRow, safeMax), wallPoint(cols - 1, backRow, safeMax), wallPoint(cols - 1, backRow, minValue), wallPoint(0, backRow, minValue)], chart.backWall?.fillColor, chart.backWall?.hidden);\n addWall(\"side\", [wallPoint(sideColumn, 0, safeMax), wallPoint(sideColumn, rows - 1, safeMax), wallPoint(sideColumn, rows - 1, minValue), wallPoint(sideColumn, 0, minValue)], chart.sideWall?.fillColor, chart.sideWall?.hidden);\n if (chart.valueAxis?.majorGridlines) {\n for (const tick of domain.ticks) {\n const edges = [\n ...(chart.backWall?.hidden ? [] : [[wallPoint(0, backRow, tick), wallPoint(cols - 1, backRow, tick)]]),\n ...(chart.sideWall?.hidden ? [] : [[wallPoint(sideColumn, 0, tick), wallPoint(sideColumn, rows - 1, tick)]])\n ];\n wallNodes.push(<path key={`wall-grid-${tick}`} fill=\"none\" stroke={chart.valueAxis.majorGridlineColor ?? wallLineColor} strokeWidth={1} d={edges.map(edge => { const [from, to] = edge.map(projectPoint); return `M ${from.x} ${from.y} L ${to.x} ${to.y}`; }).join(\" \")} />);\n }\n }\n const faces: Array<{ depth: number; node: React.ReactNode }> = [];\n for (let rowIndex = 0; rowIndex < rows - 1; rowIndex += 1) {\n for (let columnIndex = 0; columnIndex < cols - 1; columnIndex += 1) {\n const values = [matrix[rowIndex][columnIndex], matrix[rowIndex][columnIndex + 1], matrix[rowIndex + 1][columnIndex + 1], matrix[rowIndex + 1][columnIndex]];\n if (values.some(value => value == null)) continue;\n const triangles = triangulateSurfaceQuad([\n { value: values[0]!, x: columnIndex, y: rowIndex },\n { value: values[1]!, x: columnIndex + 1, y: rowIndex },\n { value: values[2]!, x: columnIndex + 1, y: rowIndex + 1 },\n { value: values[3]!, x: columnIndex, y: rowIndex + 1 }\n ], chart.valueAxis);\n triangles.forEach((triangle, triangleIndex) => {\n const world = triangle.map(point => ({\n x: point.x / Math.max(1, cols - 1),\n y: (1 - normalizeSurfaceValue(point.value, minValue, safeMax, chart.valueAxis)) * ratios.height,\n z: (1 - point.y / Math.max(1, rows - 1)) * depthScale\n }));\n const normal = transformSurfaceNormal(surfaceNormal(world[0], world[1], world[2]), chart.view3d?.rotX ?? 25, chart.view3d?.rotY ?? 30, chart.view3d?.rAngAx !== false);\n for (let band = 0; band < domain.ticks.length - 1; band += 1) {\n const lower = domain.ticks[band];\n const upper = domain.ticks[band + 1];\n const polygon = clipSurfaceBand(clipSurfaceBand(triangle, lower, true, chart.valueAxis, band === 0), upper, false, chart.valueAxis);\n if (polygon.length < 3) continue;\n const projected = polygon.map(projectPoint);\n const midpoint = (lower + upper) / 2;\n const widths = chart.raw?.bandFormatLineWidths as Record<string, number> | undefined;\n const edges = surfaceBandEdges(polygon, triangle).map(([from, to]) => [projectPoint(from), projectPoint(to)]);\n faces.push({\n depth: projected.reduce((sum, point) => sum + point.depth, 0) / projected.length,\n node: <g key={`surface-band-${rowIndex}-${columnIndex}-${triangleIndex}-${band}`}>\n {!chart.wireframe && <polygon fill={chart.surfaceMaterial === \"flat\" ? resolveSurfaceBandColor(chart, palette, domain, midpoint) : shadeSurfaceMatteColor(resolveSurfaceBandColor(chart, palette, domain, midpoint), normal)} points={projected.map(point => `${point.x},${point.y}`).join(\" \")} />}\n <path fill=\"none\" stroke={resolveSurfaceWireframeColor(chart, palette, domain, midpoint)} strokeWidth={widths?.[band] ?? chart.series[0]?.lineWidthPx ?? 1} d={edges.map(([from, to]) => `M ${from.x} ${from.y} L ${to.x} ${to.y}`).join(\" \")} />\n </g>\n });\n }\n });\n }\n }\n faces.sort((left, right) => right.depth - left.depth);\n return <g>{wallNodes}{faces.map(face => face.node)}</g>;\n}\n\nfunction renderSurfaceHitOverlay(\n chart: XlsxChart,\n layout: ChartLayout,\n selectedChartElement?: XlsxChartElementSelection | null\n) {\n const plot = resolveSurfacePlotRect(chart, layout);\n const categories = getCategoryLabels(chart);\n const rows = chart.series.length;\n const cols = Math.max(\n categories.length,\n chart.series.reduce((max, series) => Math.max(max, series.values.length), 0)\n );\n if (rows === 0 || cols === 0) {\n return null;\n }\n\n const cellWidth = plot.width / cols;\n const cellHeight = plot.height / rows;\n return (\n <g>\n {chart.series.flatMap((_, seriesIndex) => (\n Array.from({ length: cols }, (_, pointIndex) => {\n const left = plot.left + pointIndex * cellWidth;\n const top = plot.top + seriesIndex * cellHeight;\n const selected = isSelectedChartPointOrSeries(selectedChartElement, chart.id, seriesIndex, pointIndex);\n return (\n <React.Fragment key={`surface-hit-${seriesIndex}-${pointIndex}`}>\n <rect\n {...chartElementDataProps(seriesIndex, pointIndex)}\n fill=\"transparent\"\n height={cellHeight}\n stroke=\"none\"\n width={cellWidth}\n x={left}\n y={top}\n />\n {selected\n ? renderSelectionRectHandles(\n `surface-selection-${seriesIndex}-${pointIndex}`,\n left,\n top,\n cellWidth,\n cellHeight\n )\n : null}\n </React.Fragment>\n );\n })\n ))}\n </g>\n );\n}\n\nfunction indexByName(series: XlsxChart[\"series\"], matcher: RegExp) {\n const index = series.findIndex((entry) => matcher.test((entry.name ?? \"\").toLowerCase()));\n return index >= 0 ? index : null;\n}\n\nfunction renderStockChart(chart: XlsxChart, palette: ChartRendererPalette, layout: ChartLayout, selectedChartElement?: XlsxChartElementSelection | null) {\n return renderLineOrAreaChart(chart, palette, layout, \"Stock\", selectedChartElement);\n}\n\nfunction renderWaterfallChart(chart: XlsxChart, palette: ChartRendererPalette, layout: ChartLayout, selectedChartElement?: XlsxChartElementSelection | null) {\n const stages = buildChartStages(chart);\n if (stages.length === 0) {\n return null;\n }\n\n const plot = layout.plot;\n const labels = stages.map((stage) => stage.label);\n const xScale = scaleBand<string>()\n .domain(labels)\n .range([plot.left, plot.left + plot.width])\n .paddingInner(0.34)\n .paddingOuter(0.18);\n\n const bars: Array<ChartStage & { end: number; index: number; start: number }> = [];\n let runningTotal = 0;\n stages.forEach((stage, index) => {\n const start = stage.isSubtotal ? 0 : runningTotal;\n const end = stage.isSubtotal ? runningTotal : runningTotal + stage.value;\n if (!stage.isSubtotal) {\n runningTotal = end;\n }\n bars.push({ ...stage, end, index, start });\n });\n\n const extents = bars.flatMap((bar) => [0, bar.start, bar.end]);\n let minValue = Math.min(...extents);\n let maxValue = Math.max(...extents);\n if (maxValue <= minValue) {\n maxValue = minValue + 1;\n }\n\n const yScale = scaleLinear()\n .domain([minValue, maxValue])\n .range([plot.top + plot.height, plot.top]);\n const ticks = buildNumericTickValues(minValue, maxValue, chart.valueAxis?.majorUnit);\n const axisColor = chart.axisLineColor ?? chart.chartAreaBorderColor ?? palette.border;\n const labelColor = resolveChartAxisTextColor(chart);\n\n return (\n <g>\n {ticks.map((tick) => (\n <g key={`waterfall-y-${tick}`}>\n <line\n stroke={lightenColor(axisColor, 0.72)}\n strokeWidth={1}\n x1={plot.left}\n x2={plot.left + plot.width}\n y1={yScale(tick)}\n y2={yScale(tick)}\n />\n <text fill={labelColor} fontSize={10} textAnchor=\"end\" x={plot.left - 6} y={yScale(tick) + 3}>\n {formatTickValue(tick)}\n </text>\n </g>\n ))}\n <line stroke={axisColor} strokeWidth={1.2} x1={plot.left} x2={plot.left} y1={plot.top} y2={plot.top + plot.height} />\n <line stroke={axisColor} strokeWidth={1.2} x1={plot.left} x2={plot.left + plot.width} y1={yScale(0)} y2={yScale(0)} />\n {bars.map((bar, index) => {\n const bandLeft = xScale(bar.label) ?? plot.left;\n const bandWidth = xScale.bandwidth();\n const topValue = Math.max(bar.start, bar.end);\n const bottomValue = Math.min(bar.start, bar.end);\n const top = yScale(topValue);\n const height = Math.max(1, yScale(bottomValue) - top);\n const fill = bar.isSubtotal\n ? darkenColor(bar.color, 0.18)\n : bar.value >= 0\n ? bar.color\n : lightenColor(bar.color, 0.22);\n const connectorStart = index > 0 ? bars[index - 1] : null;\n const connectorY = connectorStart ? yScale(connectorStart.end) : 0;\n const selected = isSelectedChartPointOrSeries(selectedChartElement, chart.id, 0, index);\n\n return (\n <g key={`waterfall-bar-${index}`}>\n {connectorStart ? (\n <line\n stroke={lightenColor(axisColor, 0.35)}\n strokeDasharray=\"3 3\"\n strokeWidth={1}\n x1={(xScale(connectorStart.label) ?? plot.left) + xScale.bandwidth()}\n x2={bandLeft}\n y1={connectorY}\n y2={connectorY}\n />\n ) : null}\n <rect\n {...chartElementDataProps(0, index)}\n fill={fill}\n rx={2}\n ry={2}\n stroke={selected ? \"#64748b\" : darkenColor(fill, 0.22)}\n strokeWidth={selected ? 2 : 1}\n x={bandLeft}\n y={top}\n width={bandWidth}\n height={height}\n />\n {selected\n ? renderSelectionRectHandles(`waterfall-selection-${index}`, bandLeft, top, bandWidth, height)\n : null}\n <text\n fill={labelColor}\n fontSize={10}\n textAnchor=\"middle\"\n x={bandLeft + bandWidth * 0.5}\n y={plot.top + plot.height + 14}\n >\n {bar.label}\n </text>\n <text\n fill={labelColor}\n fontSize={10}\n textAnchor=\"middle\"\n x={bandLeft + bandWidth * 0.5}\n y={top - 6}\n >\n {formatTickValue(bar.end)}\n </text>\n </g>\n );\n })}\n </g>\n );\n}\n\nfunction renderFunnelChart(chart: XlsxChart, palette: ChartRendererPalette, layout: ChartLayout, selectedChartElement?: XlsxChartElementSelection | null) {\n const stages = buildChartStages(chart)\n .map((stage) => ({ ...stage, value: Math.max(0, stage.value) }))\n .filter((stage) => stage.value > 0);\n if (stages.length === 0) {\n return null;\n }\n\n const plot = layout.plot;\n const maxValue = Math.max(...stages.map((stage) => stage.value));\n const sectionHeight = plot.height / stages.length;\n const centerX = plot.left + plot.width * 0.5;\n const labelColor = resolveChartTextColor(chart);\n\n return (\n <g>\n {stages.map((stage, index) => {\n const stageWidth = (stage.value / maxValue) * plot.width;\n const topY = plot.top + index * sectionHeight;\n const stageHeight = Math.max(6, sectionHeight - 2);\n const left = centerX - stageWidth * 0.5;\n const fill = stage.isSubtotal ? darkenColor(stage.color, 0.14) : stage.color;\n const labelFitsInside = stageWidth > 90;\n const selected = isSelectedChartPointOrSeries(selectedChartElement, chart.id, 0, index);\n\n return (\n <g key={`funnel-stage-${index}`}>\n <rect\n {...chartElementDataProps(0, index)}\n fill={fill}\n height={stageHeight}\n rx={0}\n ry={0}\n stroke={selected ? \"#64748b\" : darkenColor(fill, 0.2)}\n strokeWidth={selected ? 2 : 1}\n width={stageWidth}\n x={left}\n y={topY}\n />\n {selected\n ? renderSelectionRectHandles(`funnel-selection-${index}`, left, topY, stageWidth, stageHeight)\n : null}\n <text\n fill={labelColor}\n fontSize={10}\n textAnchor={labelFitsInside ? \"middle\" : \"start\"}\n x={labelFitsInside ? centerX : centerX + stageWidth * 0.5 + 8}\n y={topY + sectionHeight * 0.5}\n >\n {`${stage.label} ${formatTickValue(stage.value)}`}\n </text>\n </g>\n );\n })}\n </g>\n );\n}\n\nfunction renderSunburstChart(chart: XlsxChart, palette: ChartRendererPalette, layout: ChartLayout, selectedChartElement?: XlsxChartElementSelection | null) {\n const hierarchyData = buildHierarchyData(chart);\n if (!hierarchyData) {\n return null;\n }\n\n const root = d3Hierarchy(hierarchyData)\n .sum((node) => node.children && node.children.length > 0 ? 0 : Math.max(0.0001, node.value ?? 0))\n .sort((left, right) => (right.value ?? 0) - (left.value ?? 0));\n const partitioned = d3Partition<ChartHierarchyDatum>()\n .size([Math.PI * 2, root.height + 1])(root);\n const plot = layout.plot;\n const radius = Math.max(24, Math.min(plot.width, plot.height) * 0.5);\n const holeRadius = radius * 0.16;\n const centerX = plot.left + plot.width * 0.5;\n const centerY = plot.top + plot.height * 0.5;\n const ringSpan = Math.max(1, partitioned.height || 1);\n const arcBuilder = d3Arc<HierarchyRectangularNode<ChartHierarchyDatum>>()\n .startAngle((node) => node.x0)\n .endAngle((node) => node.x1)\n .padAngle(0.005)\n .padRadius(radius)\n .innerRadius((node) => holeRadius + ((node.y0 - 1) / ringSpan) * (radius - holeRadius))\n .outerRadius((node) => holeRadius + ((node.y1 - 1) / ringSpan) * (radius - holeRadius) - 1);\n\n return (\n <g transform={`translate(${centerX}, ${centerY})`}>\n {partitioned.descendants().filter((node) => node.depth > 0).map((node, index) => {\n const path = arcBuilder(node);\n if (!path) {\n return null;\n }\n const labelAngle = (node.x0 + node.x1) * 0.5 - Math.PI * 0.5;\n const labelRadius = holeRadius + (((node.y0 + node.y1) * 0.5 - 1) / ringSpan) * (radius - holeRadius);\n const labelX = Math.cos(labelAngle) * labelRadius;\n const labelY = Math.sin(labelAngle) * labelRadius;\n const arcSpan = node.x1 - node.x0;\n const canShowLabel = arcSpan * labelRadius > 26;\n const fill = resolveHierarchyNodeColor(chart, node);\n const selected = isSelectedChartPointOrSeries(selectedChartElement, chart.id, 0, index);\n\n return (\n <g key={`sunburst-node-${index}`}>\n <path\n {...chartElementDataProps(0, index)}\n d={path}\n fill={fill}\n stroke={selected ? \"#64748b\" : palette.surface}\n strokeWidth={selected ? 2 : 1}\n />\n {selected\n ? renderSelectionPointHandles(`sunburst-selection-${index}`, [{ x: labelX, y: labelY }])\n : null}\n {canShowLabel ? (\n <text\n fill={darkenColor(fill, 0.65)}\n fontSize={9}\n textAnchor=\"middle\"\n transform={`translate(${labelX}, ${labelY}) rotate(${(labelAngle * 180) / Math.PI})`}\n >\n {node.data.name}\n </text>\n ) : null}\n </g>\n );\n })}\n <circle fill={chart.chartAreaFillColor ?? palette.surface} r={holeRadius - 2} />\n </g>\n );\n}\n\nfunction renderTreemapChart(chart: XlsxChart, palette: ChartRendererPalette, layout: ChartLayout, selectedChartElement?: XlsxChartElementSelection | null) {\n const hierarchyData = buildHierarchyData(chart);\n if (!hierarchyData) {\n return null;\n }\n\n const root = d3Hierarchy(hierarchyData)\n .sum((node) => node.children && node.children.length > 0 ? 0 : Math.max(0.0001, node.value ?? 0))\n .sort((left, right) => (right.value ?? 0) - (left.value ?? 0));\n const treemapRoot = d3Treemap<ChartHierarchyDatum>()\n .size([layout.plot.width, layout.plot.height])\n .paddingInner(2)\n .paddingOuter(1)\n .round(true)\n .tile(excelTreemapTile)(root);\n\n return (\n <g transform={`translate(${layout.plot.left}, ${layout.plot.top})`}>\n {treemapRoot.leaves().map((leaf, index) => {\n const fill = resolveTreemapNodeColor(chart, leaf);\n const width = Math.max(0, leaf.x1 - leaf.x0);\n const height = Math.max(0, leaf.y1 - leaf.y0);\n const canShowLabel = width > 48 && height > 22;\n const selected = isSelectedChartPointOrSeries(selectedChartElement, chart.id, 0, index);\n\n return (\n <g key={`treemap-leaf-${index}`}>\n <rect\n {...chartElementDataProps(0, index)}\n fill={fill}\n rx={3}\n ry={3}\n stroke={selected ? \"#64748b\" : palette.surface}\n strokeWidth={selected ? 2 : 1}\n x={leaf.x0}\n y={leaf.y0}\n width={width}\n height={height}\n />\n {selected\n ? renderSelectionRectHandles(`treemap-selection-${index}`, leaf.x0, leaf.y0, width, height)\n : null}\n {canShowLabel ? (\n <>\n <text\n fill={darkenColor(fill, 0.68)}\n fontSize={10}\n fontWeight={600}\n x={leaf.x0 + 8}\n y={leaf.y0 + 14}\n >\n {leaf.data.name}\n </text>\n <text\n fill={darkenColor(fill, 0.54)}\n fontSize={9}\n x={leaf.x0 + 8}\n y={leaf.y0 + 28}\n >\n {formatTickValue(leaf.value ?? 0)}\n </text>\n </>\n ) : null}\n </g>\n );\n })}\n </g>\n );\n}\n\nfunction renderBoxWhiskerChart(chart: XlsxChart, palette: ChartRendererPalette, layout: ChartLayout, selectedChartElement?: XlsxChartElementSelection | null) {\n const visibleSeries = chart.series.filter((series) => series.hidden !== true);\n if (visibleSeries.length === 0) {\n return null;\n }\n\n const seriesStats = visibleSeries.map((series, index) => ({\n color: series.color ?? chartSeriesColor(chart, typeof series.formatIdx === \"number\" ? series.formatIdx : index),\n label: normalizeCategoryLabel(series.name) || `Series ${index + 1}`,\n lineColor: series.lineColor ?? series.color ?? chartSeriesColor(chart, typeof series.formatIdx === \"number\" ? series.formatIdx : index),\n series,\n stats: computeBoxWhiskerStats(series),\n visibility: resolveBoxWhiskerVisibility(series)\n })).filter((entry): entry is {\n color: string;\n label: string;\n lineColor: string;\n series: XlsxChartSeries;\n stats: BoxWhiskerStats;\n visibility: ReturnType<typeof resolveBoxWhiskerVisibility>;\n } => entry.stats != null);\n\n if (seriesStats.length === 0) {\n return null;\n }\n\n const allValues = seriesStats.flatMap((entry) => [\n entry.stats.min,\n entry.stats.lowerWhisker,\n entry.stats.q1,\n entry.stats.median,\n entry.stats.q3,\n entry.stats.upperWhisker,\n entry.stats.max\n ]);\n const minValue = Math.min(...allValues);\n const maxValue = Math.max(...allValues);\n const valueDomain = resolveAxisDomainWithChartOverrides(chart.valueAxis, minValue, maxValue, false);\n const yScale = scaleLinear()\n .domain([valueDomain.min, valueDomain.max])\n .range([layout.plot.top + layout.plot.height, layout.plot.top]);\n const xScale = scalePoint<number>()\n .domain(seriesStats.map((_, index) => index))\n .range([layout.plot.left + 24, layout.plot.left + layout.plot.width - 24]);\n const gap = seriesStats.length > 1\n ? Math.abs((xScale(1) ?? 0) - (xScale(0) ?? 0))\n : layout.plot.width * 0.5;\n const boxWidth = clamp(gap * 0.34, 20, 54);\n const capWidth = Math.max(8, boxWidth * 0.52);\n const axisColor = chart.axisLineColor ?? chart.chartAreaBorderColor ?? palette.border;\n const labelColor = resolveChartAxisTextColor(chart);\n const meanLinePoints = seriesStats\n .filter((entry) => entry.visibility.meanLine)\n .map((entry, index) => `${xScale(index) ?? layout.plot.left},${yScale(entry.stats.mean)}`);\n\n return (\n <g>\n {valueDomain.ticks.map((tick, index) => {\n const y = yScale(tick);\n return (\n <g key={`box-whisker-grid-${index}`}>\n <line\n stroke={lightenColor(axisColor, 0.22)}\n strokeWidth={0.8}\n x1={layout.plot.left}\n x2={layout.plot.left + layout.plot.width}\n y1={y}\n y2={y}\n />\n <text\n fill={labelColor}\n fontSize={10}\n textAnchor=\"end\"\n x={layout.plot.left - 6}\n y={y + 3}\n >\n {formatTickValue(tick)}\n </text>\n </g>\n );\n })}\n <line\n stroke={axisColor}\n strokeWidth={1}\n x1={layout.plot.left}\n x2={layout.plot.left}\n y1={layout.plot.top}\n y2={layout.plot.top + layout.plot.height}\n />\n <line\n stroke={axisColor}\n strokeWidth={1}\n x1={layout.plot.left}\n x2={layout.plot.left + layout.plot.width}\n y1={layout.plot.top + layout.plot.height}\n y2={layout.plot.top + layout.plot.height}\n />\n {meanLinePoints.length >= 2 ? (\n <polyline\n fill=\"none\"\n points={meanLinePoints.join(\" \")}\n stroke={darkenColor(axisColor, 0.2)}\n strokeDasharray=\"4 3\"\n strokeWidth={1}\n />\n ) : null}\n {seriesStats.map((entry, index) => {\n const x = xScale(index) ?? layout.plot.left;\n const boxTop = yScale(entry.stats.q3);\n const boxBottom = yScale(entry.stats.q1);\n const medianY = yScale(entry.stats.median);\n const lowerWhiskerY = yScale(entry.stats.lowerWhisker);\n const upperWhiskerY = yScale(entry.stats.upperWhisker);\n const meanY = yScale(entry.stats.mean);\n const visiblePoints = entry.visibility.nonoutliers\n ? entry.stats.visiblePoints\n : [];\n const outliers = entry.visibility.outliers\n ? entry.stats.outliers\n : [];\n const selected = isSelectedChartPointOrSeries(selectedChartElement, chart.id, index, index);\n\n return (\n <g {...chartElementDataProps(index)} key={`box-whisker-series-${index}`}>\n <line\n stroke={entry.lineColor}\n strokeWidth={1.5}\n x1={x}\n x2={x}\n y1={upperWhiskerY}\n y2={boxTop}\n />\n <line\n stroke={entry.lineColor}\n strokeWidth={1.5}\n x1={x}\n x2={x}\n y1={boxBottom}\n y2={lowerWhiskerY}\n />\n <line\n stroke={entry.lineColor}\n strokeWidth={1.5}\n x1={x - capWidth * 0.5}\n x2={x + capWidth * 0.5}\n y1={upperWhiskerY}\n y2={upperWhiskerY}\n />\n <line\n stroke={entry.lineColor}\n strokeWidth={1.5}\n x1={x - capWidth * 0.5}\n x2={x + capWidth * 0.5}\n y1={lowerWhiskerY}\n y2={lowerWhiskerY}\n />\n <rect\n {...chartElementDataProps(index, index)}\n fill={lightenColor(entry.color, 0.35)}\n fillOpacity={0.72}\n height={Math.max(1, boxBottom - boxTop)}\n stroke={selected ? \"#64748b\" : entry.lineColor}\n strokeWidth={selected ? 2 : 1.5}\n width={boxWidth}\n x={x - boxWidth * 0.5}\n y={boxTop}\n />\n {selected\n ? renderSelectionRectHandles(\n `box-whisker-selection-${index}`,\n x - boxWidth * 0.5,\n boxTop,\n boxWidth,\n Math.max(1, boxBottom - boxTop)\n )\n : null}\n <line\n stroke={darkenColor(entry.lineColor, 0.15)}\n strokeWidth={2}\n x1={x - boxWidth * 0.5}\n x2={x + boxWidth * 0.5}\n y1={medianY}\n y2={medianY}\n />\n {entry.visibility.meanMarker ? (\n <>\n <line\n stroke={darkenColor(entry.lineColor, 0.18)}\n strokeWidth={1.2}\n x1={x - 4}\n x2={x + 4}\n y1={meanY - 4}\n y2={meanY + 4}\n />\n <line\n stroke={darkenColor(entry.lineColor, 0.18)}\n strokeWidth={1.2}\n x1={x - 4}\n x2={x + 4}\n y1={meanY + 4}\n y2={meanY - 4}\n />\n </>\n ) : null}\n {visiblePoints.map((value, pointIndex) => {\n const y = yScale(value);\n const jitter = ((pointIndex % 7) - 3) * (boxWidth / 16);\n return (\n <circle\n {...chartElementDataProps(index, pointIndex)}\n key={`box-whisker-visible-${index}-${pointIndex}`}\n cx={x + jitter}\n cy={y}\n fill={entry.color}\n fillOpacity={0.45}\n r={2}\n stroke=\"none\"\n />\n );\n })}\n {outliers.map((value, pointIndex) => {\n const y = yScale(value);\n return (\n <circle\n {...chartElementDataProps(index, pointIndex)}\n key={`box-whisker-outlier-${index}-${pointIndex}`}\n cx={x}\n cy={y}\n fill=\"#ffffff\"\n r={3}\n stroke={entry.lineColor}\n strokeWidth={1.2}\n />\n );\n })}\n <text\n fill={labelColor}\n fontSize={10}\n textAnchor=\"middle\"\n x={x}\n y={layout.plot.top + layout.plot.height + 14}\n >\n {entry.label}\n </text>\n </g>\n );\n })}\n </g>\n );\n}\n\nfunction renderRegionMapChart(\n chart: XlsxChart,\n palette: ChartRendererPalette,\n layout: ChartLayout,\n selectedChartElement: XlsxChartElementSelection | null | undefined,\n { geoIdentity, geoMercator, geoNaturalEarth1, geoPath, resolveRegionMapFeatureSet, resolveRegionMapFeature, getRegionMapBaseFeatures }: RegionMapResources\n) {\n const primarySeriesIndex = Math.max(0, chart.series.findIndex((series) => series.hidden !== true));\n const primarySeries = chart.series[primarySeriesIndex] ?? null;\n if (!primarySeries) {\n return null;\n }\n\n const labels = getCategoryLabels(chart);\n const layoutProperties = resolveRegionMapLayoutProperties(primarySeries);\n const geography = layoutProperties?.geography && typeof layoutProperties.geography === \"object\"\n ? layoutProperties.geography as Record<string, unknown>\n : null;\n const featureSet = resolveRegionMapFeatureSet(labels, geography);\n const viewedRegionType = typeof geography?.viewedRegionType === \"string\"\n ? geography.viewedRegionType\n : null;\n const projectionType = typeof geography?.projectionType === \"string\"\n ? geography.projectionType\n : null;\n const projection = featureSet === \"us-state\"\n ? geoIdentity()\n : projectionType === \"miller\"\n ? geoMercator()\n : geoNaturalEarth1();\n const availableFeatures = getRegionMapBaseFeatures(featureSet);\n const categoricalValues = resolveRegionMapColorStrings(primarySeries);\n const categoricalColorByLabel = categoricalValues\n ? new Map(\n Array.from(new Set(categoricalValues.filter(Boolean))).map((value, index) => [\n value,\n chartPointColor(chart, index, primarySeriesIndex)\n ])\n )\n : null;\n const entries = labels.map((label, index) => {\n const feature = resolveRegionMapFeature(label, featureSet);\n const value = safeNumber(primarySeries.values[index]);\n const colorLabel = categoricalValues?.[index] || null;\n return {\n colorLabel,\n feature,\n key: normalizeCategoryLabel(label),\n label: normalizeCategoryLabel(label),\n value\n };\n }).filter((entry) => entry.feature != null && (entry.value != null || entry.colorLabel != null)) as Array<{\n colorLabel: string | null;\n feature: RegionMapFeature;\n key: string;\n label: string;\n value: number | null;\n }>;\n const fitToMatchedData = entries.length > 0 && (viewedRegionType === \"dataOnly\" || entries.length === 1);\n const fitFeatures = fitToMatchedData\n ? entries.map((entry) => entry.feature)\n : availableFeatures;\n projection.fitExtent(\n [\n [layout.plot.left + 8, layout.plot.top + 8],\n [layout.plot.left + layout.plot.width - 8, layout.plot.top + layout.plot.height - 8]\n ],\n {\n type: \"FeatureCollection\",\n features: fitFeatures\n } satisfies FeatureCollection<Geometry, { name?: string }>\n );\n const path = geoPath(projection);\n const baseFeatures = fitToMatchedData\n ? fitFeatures\n : availableFeatures;\n const noDataFill = resolveRegionMapNoDataColor(chart, primarySeriesIndex);\n const outlineColor = chart.chartAreaBorderColor && chart.chartAreaBorderColor !== \"transparent\"\n ? chart.chartAreaBorderColor\n : darkenColor(noDataFill, 0.22);\n const numericEntryValues = primarySeries.values\n .map(safeNumber)\n .filter((value): value is number => typeof value === \"number\" && Number.isFinite(value));\n const minValue = numericEntryValues.length > 0 ? Math.min(...numericEntryValues) : 0;\n const maxValue = numericEntryValues.length > 0 ? Math.max(...numericEntryValues) : 1;\n const showRegionLabels = layoutProperties?.regionLabelLayout !== \"none\";\n\n return (\n <g>\n {baseFeatures.map((feature, index) => {\n const d = path(feature);\n if (!d) {\n return null;\n }\n return (\n <path\n d={d}\n fill={noDataFill}\n key={`region-map-base-${feature.id ?? \"feature\"}-${index}`}\n stroke={outlineColor}\n strokeLinejoin=\"round\"\n strokeWidth={0.6}\n />\n );\n })}\n {entries.map((entry, index) => {\n const d = path(entry.feature);\n if (!d) {\n return null;\n }\n const fill = entry.value != null\n ? (() => {\n const ratio = maxValue <= minValue ? 1 : (entry.value - minValue) / Math.max(1e-6, maxValue - minValue);\n return resolveRegionMapValueColor(chart, primarySeriesIndex, ratio);\n })()\n : categoricalColorByLabel?.get(entry.colorLabel ?? \"\") ?? resolveRegionMapDataColor(chart, primarySeriesIndex);\n const selected = isSelectedChartPointOrSeries(selectedChartElement, chart.id, primarySeriesIndex, index);\n const centroid = path.centroid(entry.feature);\n const canShowSelectionDot = Number.isFinite(centroid[0]) && Number.isFinite(centroid[1]);\n return (\n <React.Fragment key={`region-map-value-${entry.key || index}`}>\n <path\n {...chartElementDataProps(primarySeriesIndex, index)}\n d={d}\n fill={fill}\n stroke={selected ? \"#64748b\" : darkenColor(fill, 0.18)}\n strokeLinejoin=\"round\"\n strokeWidth={selected ? 1.8 : 0.85}\n />\n {selected && canShowSelectionDot\n ? renderSelectionPointHandles(`region-map-selection-${index}`, [{ x: centroid[0], y: centroid[1] }])\n : null}\n </React.Fragment>\n );\n })}\n {showRegionLabels\n ? entries.map((entry, index) => {\n const bounds = path.bounds(entry.feature);\n const [[x0, y0], [x1, y1]] = bounds;\n const width = x1 - x0;\n const height = y1 - y0;\n if (!Number.isFinite(width) || !Number.isFinite(height) || width < 26 || height < 12) {\n return null;\n }\n const centroid = path.centroid(entry.feature);\n if (!Number.isFinite(centroid[0]) || !Number.isFinite(centroid[1])) {\n return null;\n }\n return (\n <text\n fill={resolveChartTextColor(chart)}\n fontSize={9}\n fontWeight={600}\n key={`region-map-label-${entry.key || index}`}\n textAnchor=\"middle\"\n x={centroid[0]}\n y={centroid[1]}\n >\n {truncateSvgText(entry.label, Math.max(28, width - 4), 9)}\n </text>\n );\n })\n : null}\n </g>\n );\n}\n\nfunction renderUnsupported(chart: XlsxChart, palette: ChartRendererPalette, layout: ChartLayout, chartType: string) {\n return (\n <g>\n <rect\n fill={lightenColor(chart.chartAreaFillColor ?? palette.surface, 0.02)}\n height={layout.plot.height}\n stroke={lightenColor(chart.axisLineColor ?? palette.border, 0.2)}\n strokeDasharray=\"3 3\"\n width={layout.plot.width}\n x={layout.plot.left}\n y={layout.plot.top}\n />\n <text\n fill={resolveChartMutedTextColor(chart)}\n fontSize={11}\n textAnchor=\"middle\"\n x={layout.plot.left + layout.plot.width / 2}\n y={layout.plot.top + layout.plot.height / 2}\n >\n {`Unsupported chart type: ${chartType}`}\n </text>\n </g>\n );\n}\n\nfunction renderChartPlot(\n chart: XlsxChart,\n palette: ChartRendererPalette,\n layout: ChartLayout,\n chartType: string,\n selectedChartElement?: XlsxChartElementSelection | null\n) {\n if (isComboChart(chart)) {\n return renderComboChart(chart, palette, layout, selectedChartElement) ?? renderUnsupported(chart, palette, layout, \"Combo\");\n }\n if (\n chartType === \"ColumnClustered\"\n || chartType === \"ColumnStacked\"\n || chartType === \"ColumnPercentStacked\"\n || chartType === \"BarClustered\"\n || chartType === \"BarStacked\"\n || chartType === \"BarPercentStacked\"\n ) {\n return renderBarChart(chart, palette, layout, chartType, selectedChartElement);\n }\n if (\n chartType === \"Line\"\n || chartType === \"LineStacked\"\n || chartType === \"LinePercentStacked\"\n || chartType === \"Area\"\n || chartType === \"AreaStacked\"\n || chartType === \"AreaPercentStacked\"\n ) {\n return renderLineOrAreaChart(chart, palette, layout, chartType, selectedChartElement);\n }\n if (chartType === \"Scatter\") {\n return renderScatterChart(chart, palette, layout, false, selectedChartElement);\n }\n if (chartType === \"ScatterLines\") {\n return renderScatterChart(chart, palette, layout, false, selectedChartElement);\n }\n if (chartType === \"ScatterSmooth\") {\n return renderScatterChart(chart, palette, layout, true, selectedChartElement);\n }\n if (chartType === \"Bubble\") {\n return renderBubbleChart(chart, palette, layout, selectedChartElement);\n }\n if (chartType === \"Radar\") {\n return renderRadarChart(chart, palette, layout, selectedChartElement);\n }\n if (chartType === \"Pie\" || chartType === \"Pie3D\" || chartType === \"PieExploded\" || chartType === \"Doughnut\") {\n return renderPieChart(chart, palette, layout, chartType, selectedChartElement);\n }\n if (chartType === \"BarOfPie\") {\n return renderBarOfPieChart(chart, palette, layout, selectedChartElement);\n }\n if (chartType === \"Surface\") {\n return renderSurfaceChart(chart, palette, layout, selectedChartElement);\n }\n if (chartType === \"Stock\") {\n return renderStockChart(chart, palette, layout, selectedChartElement);\n }\n if (chartType === \"Waterfall\") {\n return renderWaterfallChart(chart, palette, layout, selectedChartElement);\n }\n if (chartType === \"Funnel\") {\n return renderFunnelChart(chart, palette, layout, selectedChartElement);\n }\n if (chartType === \"BoxWhisker\") {\n return renderBoxWhiskerChart(chart, palette, layout, selectedChartElement);\n }\n if (chartType === \"Sunburst\") {\n return renderSunburstChart(chart, palette, layout, selectedChartElement);\n }\n if (chartType === \"Treemap\") {\n return renderTreemapChart(chart, palette, layout, selectedChartElement);\n }\n if (chartType === \"RegionMap\") {\n return <RegionMapPlot chart={chart} layout={layout} palette={palette} selectedChartElement={selectedChartElement} />;\n }\n return renderUnsupported(chart, palette, layout, chartType);\n}\n\nexport const MemoChartSvg = React.memo(function MemoChartSvg({\n chart,\n onChartElementDoubleClick,\n onChartElementPointerDown,\n palette,\n rect,\n selectedChartElement\n}: ChartSvgProps) {\n const renderChartType = normalizeRenderableChartType(chart);\n const legendItems = getLegendItems(chart, renderChartType, palette);\n const layout = buildLayout(chart, rect, legendItems);\n const chartRaw = chart.raw && typeof chart.raw === \"object\" ? chart.raw as Record<string, unknown> : null;\n const explicitNoFill = chartRaw?.chartAreaNoFill === true || chartRaw?.plotAreaNoFill === true;\n const background = chart.chartAreaFillColor ?? (explicitNoFill ? \"transparent\" : \"#ffffff\");\n const borderColor = chart.chartAreaBorderColor ?? \"transparent\";\n const normalizedBackground = background.trim().toLowerCase();\n const normalizedBorderColor = borderColor.trim().toLowerCase();\n const hideBackgroundRect = normalizedBackground === \"transparent\" && normalizedBorderColor === \"transparent\";\n const fontFamily = buildChartFontFamily(chart.fontFamily);\n const handlePointerDown = React.useCallback((event: React.PointerEvent<SVGSVGElement>) => {\n const selection = resolveChartSelectionFromTarget(chart, event.target, selectedChartElement);\n if (!selection) {\n return;\n }\n\n if (resolveChartElementTarget(event.target)) {\n event.stopPropagation();\n }\n onChartElementPointerDown?.(selection, event);\n }, [chart, onChartElementPointerDown, selectedChartElement]);\n const handleDoubleClick = React.useCallback((event: React.MouseEvent<SVGSVGElement>) => {\n const selection = resolveChartSelectionFromTarget(chart, event.target, selectedChartElement);\n if (!selection) {\n return;\n }\n\n if (resolveChartElementTarget(event.target)) {\n event.stopPropagation();\n }\n onChartElementDoubleClick?.(selection, event);\n }, [chart, onChartElementDoubleClick, selectedChartElement]);\n\n const renderSvgChart = (plot: React.ReactNode) => (\n <svg\n aria-label={chart.title ?? chart.name ?? \"Chart\"}\n onDoubleClick={handleDoubleClick}\n onPointerDown={handlePointerDown}\n role=\"img\"\n style={{ display: \"block\", fontFamily, height: \"100%\", pointerEvents: \"auto\", width: \"100%\" }}\n viewBox={`0 0 ${layout.width} ${layout.height}`}\n >\n {hideBackgroundRect\n ? null\n : <rect fill={background} height={layout.height} stroke={borderColor} strokeWidth={1} width={layout.width} x={0} y={0} />}\n {renderTitle(chart, layout, palette)}\n {renderLegend(chart, layout, palette)}\n {plot}\n </svg>\n );\n if (renderChartType === \"Surface\") {\n const surfacePlot = renderSurfaceChart(chart, palette, layout, selectedChartElement);\n return (\n <SurfaceChartComposite\n loadingFallback={renderSvgChart(surfacePlot)}\n background={background}\n borderColor={borderColor}\n chart={chart}\n fallback={surfacePlot}\n fontFamily={fontFamily}\n layout={layout}\n onDoubleClick={handleDoubleClick}\n onPointerDown={handlePointerDown}\n overlay={\n <>\n {renderSurfaceHitOverlay(chart, layout, selectedChartElement)}\n {renderSurfaceAxes(chart, layout)}\n {renderTitle(chart, layout, palette)}\n {renderLegend(chart, layout, palette)}\n </>\n }\n palette={palette}\n />\n );\n }\n\n return renderSvgChart(renderChartPlot(chart, palette, layout, renderChartType, selectedChartElement));\n}, (prev, next) => (\n prev.chart === next.chart\n && prev.onChartElementDoubleClick === next.onChartElementDoubleClick\n && prev.onChartElementPointerDown === next.onChartElementPointerDown\n && prev.palette === next.palette\n && prev.rect.height === next.rect.height\n && prev.rect.width === next.rect.width\n && prev.rect.left === next.rect.left\n && prev.rect.top === next.rect.top\n && prev.selectedChartElement === next.selectedChartElement\n));\n"]}
|