From 4544603c55635b36d8922fc2b0e09ffed28b79e1 Mon Sep 17 00:00:00 2001 From: Faran Javed Date: Fri, 3 Jul 2026 02:17:04 +0500 Subject: [PATCH] fix theme echart definition and formatter --- .../src/comps/barChartComp/barChartUtils.ts | 36 ++++--- .../chartConfigs/cartesianAxisConfig.tsx | 43 +++++---- .../src/comps/basicChartComp/chartUtils.ts | 26 ++--- .../boxplotChartComp/boxplotChartComp.tsx | 1 + .../boxplotChartComp/boxplotChartUtils.ts | 35 ++++--- .../candleStickChartUtils.ts | 66 +++++++------ .../chartConfigs/cartesianAxisConfig.tsx | 43 +++++---- .../src/comps/chartComp/chartUtils.ts | 26 ++--- .../heatmapChartComp/heatmapChartUtils.ts | 43 +++++---- .../src/comps/lineChartComp/lineChartUtils.ts | 36 ++++--- .../scatterChartComp/scatterChartUtils.ts | 39 ++++---- .../src/util/echartsThemeUtils.ts | 94 +++++++++++++++++++ 12 files changed, 314 insertions(+), 174 deletions(-) create mode 100644 client/packages/lowcoder-comps/src/util/echartsThemeUtils.ts diff --git a/client/packages/lowcoder-comps/src/comps/barChartComp/barChartUtils.ts b/client/packages/lowcoder-comps/src/comps/barChartComp/barChartUtils.ts index 84b4ea05c6..2bccf30d8f 100644 --- a/client/packages/lowcoder-comps/src/comps/barChartComp/barChartUtils.ts +++ b/client/packages/lowcoder-comps/src/comps/barChartComp/barChartUtils.ts @@ -16,6 +16,7 @@ import opacityToHex from "../../util/opacityToHex"; import parseBackground from "../../util/gradientBackgroundColor"; import {ba} from "@fullcalendar/core/internal-common"; import {chartStyleWrapper, styleWrapper} from "../../util/styleWrapper"; +import { mergeCartesianAxis } from "../../util/echartsThemeUtils"; export function transformData( originData: JSONObject[], @@ -310,22 +311,27 @@ export function getEchartsConfig( ); config = { ...config, + xAxis: mergeCartesianAxis( + theme, + finalXyConfig.xConfig.type, + finalXyConfig.xConfig, + props?.xAxisStyle, + 11, + { + data: finalXyConfig.xConfig.type === "category" && (props.xAxisData as []).length!==0?props?.xAxisData:transformedData.map((i: any) => i[props.xAxisKey]), + } + ), // @ts-ignore - xAxis: { - ...finalXyConfig.xConfig, - axisLabel: { - ...styleWrapper(props?.xAxisStyle, theme?.xAxisStyle, 11) - }, - data: finalXyConfig.xConfig.type === "category" && (props.xAxisData as []).length!==0?props?.xAxisData:transformedData.map((i: any) => i[props.xAxisKey]), - }, - // @ts-ignore - yAxis: { - ...finalXyConfig.yConfig, - axisLabel: { - ...styleWrapper(props?.yAxisStyle, theme?.yAxisStyle, 11) - }, - data: finalXyConfig.yConfig.type === "category" && (props.xAxisData as []).length!==0?props?.xAxisData:transformedData.map((i: any) => i[props.xAxisKey]), - }, + yAxis: mergeCartesianAxis( + theme, + finalXyConfig.yConfig.type, + finalXyConfig.yConfig, + props?.yAxisStyle, + 11, + { + data: finalXyConfig.yConfig.type === "category" && (props.xAxisData as []).length!==0?props?.xAxisData:transformedData.map((i: any) => i[props.xAxisKey]), + } + ), }; if(props.chartConfig.race) { diff --git a/client/packages/lowcoder-comps/src/comps/basicChartComp/chartConfigs/cartesianAxisConfig.tsx b/client/packages/lowcoder-comps/src/comps/basicChartComp/chartConfigs/cartesianAxisConfig.tsx index da4d702214..e0b22a2c7a 100644 --- a/client/packages/lowcoder-comps/src/comps/basicChartComp/chartConfigs/cartesianAxisConfig.tsx +++ b/client/packages/lowcoder-comps/src/comps/basicChartComp/chartConfigs/cartesianAxisConfig.tsx @@ -1,6 +1,5 @@ import { XAXisComponentOption, YAXisComponentOption } from "echarts"; import { ChartSize, XAxisDirectionType } from "../chartConstants"; -import { i18n } from "lowcoder-core"; import { MultiCompBuilder, withContext, @@ -11,9 +10,27 @@ import { isNumeric, } from "lowcoder-sdk"; import { i18nObjs, trans } from "i18n/comps"; -import _, { isNil } from "lodash"; +import _ from "lodash"; import { xAxisTypeUrl } from "./chartUrls"; +/** Y-axis format from Properties; undefined when the format field is left empty. */ +function buildUserAxisLabelFormatter(formatEvaluator: unknown) { + if (typeof formatEvaluator !== "function") { + return undefined; + } + const evaluate = formatEvaluator as (ctx: { value: unknown }) => string; + const sample = evaluate({ value: 0 }); + if (sample == null || String(sample).trim() === "") { + return undefined; + } + return { + formatter: (value: string | number) => { + const formatted = evaluate({ value }); + return formatted != null && formatted !== "" ? formatted : String(value); + }, + }; +} + const XAxisTypeOptions = [ { label: trans("chart.auto"), @@ -137,24 +154,10 @@ export const YAxisConfig = (function () { align: "left", }, }; - const numberFormat = new Intl.NumberFormat(i18n.locales, { - notation: "compact", - }); - (config.axisLabel as any) = { - formatter: (value: string | number) => { - const res = (props.formatter as any)({ value: value }); - if (!isNil(res) && res !== "") { - return res; - } - if ( - (props.yAxisType === "value" || props.yAxisType === "log") && - typeof value === "number" - ) { - return numberFormat.format(value); - } - return value + ""; - }, - }; + const userAxisLabel = buildUserAxisLabelFormatter(props.formatter); + if (userAxisLabel) { + (config.axisLabel as any) = userAxisLabel; + } if (props.yAxisType === "log") { (config as any).logBase = props.logBase || 10; } diff --git a/client/packages/lowcoder-comps/src/comps/basicChartComp/chartUtils.ts b/client/packages/lowcoder-comps/src/comps/basicChartComp/chartUtils.ts index 6c50206902..6a0a2ecc2c 100644 --- a/client/packages/lowcoder-comps/src/comps/basicChartComp/chartUtils.ts +++ b/client/packages/lowcoder-comps/src/comps/basicChartComp/chartUtils.ts @@ -13,6 +13,7 @@ import { calcXYConfig } from "comps/chartComp/chartConfigs/cartesianAxisConfig"; import Big from "big.js"; import { googleMapsApiUrl } from "./chartConfigs/chartUrls"; import {chartStyleWrapper, styleWrapper} from "../../util/styleWrapper"; +import { mergeCartesianAxis } from "../../util/echartsThemeUtils"; import parseBackground from "../../util/gradientBackgroundColor"; export function transformData( @@ -260,20 +261,19 @@ export function getEchartsConfig( ); config = { ...config, + xAxis: mergeCartesianAxis( + theme, + finalXyConfig.xConfig.type, + finalXyConfig.xConfig, + props?.xAxisStyle + ), // @ts-ignore - xAxis: { - ...finalXyConfig.xConfig, - axisLabel: { - ...styleWrapper(props?.xAxisStyle, theme?.xAxisStyle, 11) - } - }, - // @ts-ignore - yAxis: { - ...finalXyConfig.yConfig, - axisLabel: { - ...styleWrapper(props?.yAxisStyle, theme?.yAxisStyle, 11) - } - }, + yAxis: mergeCartesianAxis( + theme, + finalXyConfig.yConfig.type, + finalXyConfig.yConfig, + props?.yAxisStyle + ), }; } // console.log("Echarts transformedData and config", transformedData, config); diff --git a/client/packages/lowcoder-comps/src/comps/boxplotChartComp/boxplotChartComp.tsx b/client/packages/lowcoder-comps/src/comps/boxplotChartComp/boxplotChartComp.tsx index 2cc9c27933..59c2bf5cb6 100644 --- a/client/packages/lowcoder-comps/src/comps/boxplotChartComp/boxplotChartComp.tsx +++ b/client/packages/lowcoder-comps/src/comps/boxplotChartComp/boxplotChartComp.tsx @@ -175,6 +175,7 @@ BoxplotChartTmpComp = withViewFn(BoxplotChartTmpComp, (comp) => { notMerge lazyUpdate opts={{ locale: getEchartsLocale() }} + theme={themeConfig} option={option} mode={mode} /> diff --git a/client/packages/lowcoder-comps/src/comps/boxplotChartComp/boxplotChartUtils.ts b/client/packages/lowcoder-comps/src/comps/boxplotChartComp/boxplotChartUtils.ts index 2bc1904d47..ef09deb3dc 100644 --- a/client/packages/lowcoder-comps/src/comps/boxplotChartComp/boxplotChartUtils.ts +++ b/client/packages/lowcoder-comps/src/comps/boxplotChartComp/boxplotChartUtils.ts @@ -8,6 +8,7 @@ import _ from "lodash"; import { googleMapsApiUrl } from "../basicChartComp/chartConfigs/chartUrls"; import parseBackground from "../../util/gradientBackgroundColor"; import {chartStyleWrapper, styleWrapper} from "../../util/styleWrapper"; +import { mergeCartesianAxis } from "../../util/echartsThemeUtils"; // Define the configuration interface to match the original transform interface AggregateConfig { @@ -155,21 +156,25 @@ export function getEchartsConfig( ...gridPos, containLabel: true, }, - xAxis: { - name: props.xAxisKey, - nameLocation: 'middle', - nameGap: 30, - scale: true, - axisLabel: { - ...styleWrapper(props?.xAxisStyle, theme?.xAxisStyle, 11) - } - }, - yAxis: { - type: "category", - axisLabel: { - ...styleWrapper(props?.yAxisStyle, theme?.yAxisStyle, 11) - } - }, + xAxis: mergeCartesianAxis( + theme, + "value", + { + name: props.xAxisKey, + nameLocation: 'middle', + nameGap: 30, + scale: true, + }, + props?.xAxisStyle + ), + yAxis: mergeCartesianAxis( + theme, + "category", + { + type: "category", + }, + props?.yAxisStyle + ), dataset: [ { id: 'raw', diff --git a/client/packages/lowcoder-comps/src/comps/candleStickChartComp/candleStickChartUtils.ts b/client/packages/lowcoder-comps/src/comps/candleStickChartComp/candleStickChartUtils.ts index ef079c6a2c..7c78f5768d 100644 --- a/client/packages/lowcoder-comps/src/comps/candleStickChartComp/candleStickChartUtils.ts +++ b/client/packages/lowcoder-comps/src/comps/candleStickChartComp/candleStickChartUtils.ts @@ -15,6 +15,7 @@ import { googleMapsApiUrl } from "../chartComp/chartConfigs/chartUrls"; import { useContext } from "react"; import parseBackground from "../../util/gradientBackgroundColor"; import {styleWrapper} from "../../util/styleWrapper"; +import { mergeCartesianAxis } from "../../util/echartsThemeUtils"; export function transformData( originData: JSONObject[], @@ -172,39 +173,44 @@ export function getEchartsConfig( height: props?.dataZoomHeight } ], - yAxis: { - type: "value", - scale: true, - splitArea: props?.axisFlagVisibility && { - show: true, - areaStyle: { - color: props?.echartsData?.axisColor || props?.echartsOption?.axisColor - } - }, - axisLabel: { - ...styleWrapper(props?.yAxisStyle, theme?.yAxisStyle, 13), - } - }, - xAxis: props?.echartsOption && { - type: 'category', - data: props?.echartsTitleData.length && props?.echartsTitleData || props?.echartsData.xAxis && props?.echartsData.xAxis.data || props?.echartsOption.xAxis && props?.echartsOption.xAxis.data, - splitArea: !props?.axisFlagVisibility && { - show: true, - areaStyle: { - // Provide multiple colors to alternate through - color: props?.echartsData?.axisColor || props?.echartsOption?.axisColor + yAxis: mergeCartesianAxis( + theme, + "value", + { + type: "value", + scale: true, + splitArea: props?.axisFlagVisibility && { + show: true, + areaStyle: { + color: props?.echartsData?.axisColor || props?.echartsOption?.axisColor + } }, }, - axisLabel: { - ...styleWrapper(props?.xAxisStyle, theme?.xAxisStyle, 13), - }, - boundaryGap: true, - // Turn off x-axis split lines if desired, so you only see colored areas - splitLine: { - show: false + props?.yAxisStyle, + 13 + ), + xAxis: props?.echartsOption && mergeCartesianAxis( + theme, + "category", + { + type: 'category', + data: props?.echartsTitleData.length && props?.echartsTitleData || props?.echartsData.xAxis && props?.echartsData.xAxis.data || props?.echartsOption.xAxis && props?.echartsOption.xAxis.data, + boundaryGap: true, + splitLine: { + show: false + }, }, - // Show split areas, each day with a different background color - }, + props?.xAxisStyle, + 13, + { + splitArea: !props?.axisFlagVisibility && { + show: true, + areaStyle: { + color: props?.echartsData?.axisColor || props?.echartsOption?.axisColor + }, + }, + } + ), series: props?.echartsOption && [ { name: props?.echartsConfig.type, diff --git a/client/packages/lowcoder-comps/src/comps/chartComp/chartConfigs/cartesianAxisConfig.tsx b/client/packages/lowcoder-comps/src/comps/chartComp/chartConfigs/cartesianAxisConfig.tsx index da4d702214..e0b22a2c7a 100644 --- a/client/packages/lowcoder-comps/src/comps/chartComp/chartConfigs/cartesianAxisConfig.tsx +++ b/client/packages/lowcoder-comps/src/comps/chartComp/chartConfigs/cartesianAxisConfig.tsx @@ -1,6 +1,5 @@ import { XAXisComponentOption, YAXisComponentOption } from "echarts"; import { ChartSize, XAxisDirectionType } from "../chartConstants"; -import { i18n } from "lowcoder-core"; import { MultiCompBuilder, withContext, @@ -11,9 +10,27 @@ import { isNumeric, } from "lowcoder-sdk"; import { i18nObjs, trans } from "i18n/comps"; -import _, { isNil } from "lodash"; +import _ from "lodash"; import { xAxisTypeUrl } from "./chartUrls"; +/** Y-axis format from Properties; undefined when the format field is left empty. */ +function buildUserAxisLabelFormatter(formatEvaluator: unknown) { + if (typeof formatEvaluator !== "function") { + return undefined; + } + const evaluate = formatEvaluator as (ctx: { value: unknown }) => string; + const sample = evaluate({ value: 0 }); + if (sample == null || String(sample).trim() === "") { + return undefined; + } + return { + formatter: (value: string | number) => { + const formatted = evaluate({ value }); + return formatted != null && formatted !== "" ? formatted : String(value); + }, + }; +} + const XAxisTypeOptions = [ { label: trans("chart.auto"), @@ -137,24 +154,10 @@ export const YAxisConfig = (function () { align: "left", }, }; - const numberFormat = new Intl.NumberFormat(i18n.locales, { - notation: "compact", - }); - (config.axisLabel as any) = { - formatter: (value: string | number) => { - const res = (props.formatter as any)({ value: value }); - if (!isNil(res) && res !== "") { - return res; - } - if ( - (props.yAxisType === "value" || props.yAxisType === "log") && - typeof value === "number" - ) { - return numberFormat.format(value); - } - return value + ""; - }, - }; + const userAxisLabel = buildUserAxisLabelFormatter(props.formatter); + if (userAxisLabel) { + (config.axisLabel as any) = userAxisLabel; + } if (props.yAxisType === "log") { (config as any).logBase = props.logBase || 10; } diff --git a/client/packages/lowcoder-comps/src/comps/chartComp/chartUtils.ts b/client/packages/lowcoder-comps/src/comps/chartComp/chartUtils.ts index 292f5047ca..a0e2e0d1df 100644 --- a/client/packages/lowcoder-comps/src/comps/chartComp/chartUtils.ts +++ b/client/packages/lowcoder-comps/src/comps/chartComp/chartUtils.ts @@ -13,6 +13,7 @@ import { calcXYConfig } from "comps/chartComp/chartConfigs/cartesianAxisConfig"; import Big from "big.js"; import { googleMapsApiUrl } from "./chartConfigs/chartUrls"; import {chartStyleWrapper, styleWrapper} from "../../util/styleWrapper"; +import { mergeCartesianAxis } from "../../util/echartsThemeUtils"; import parseBackground from "../../util/gradientBackgroundColor"; export function transformData( @@ -257,20 +258,19 @@ export function getEchartsConfig( ); config = { ...config, + xAxis: mergeCartesianAxis( + theme, + finalXyConfig.xConfig.type, + finalXyConfig.xConfig, + props?.xAxisStyle + ), // @ts-ignore - xAxis: { - ...finalXyConfig.xConfig, - axisLabel: { - ...styleWrapper(props?.xAxisStyle, theme?.xAxisStyle, 11) - } - }, - // @ts-ignore - yAxis: { - ...finalXyConfig.yConfig, - axisLabel: { - ...styleWrapper(props?.yAxisStyle, theme?.yAxisStyle, 11) - } - }, + yAxis: mergeCartesianAxis( + theme, + finalXyConfig.yConfig.type, + finalXyConfig.yConfig, + props?.yAxisStyle + ), }; } // log.log("Echarts transformedData and config", transformedData, config); diff --git a/client/packages/lowcoder-comps/src/comps/heatmapChartComp/heatmapChartUtils.ts b/client/packages/lowcoder-comps/src/comps/heatmapChartComp/heatmapChartUtils.ts index 80b04f59d8..06481fe47f 100644 --- a/client/packages/lowcoder-comps/src/comps/heatmapChartComp/heatmapChartUtils.ts +++ b/client/packages/lowcoder-comps/src/comps/heatmapChartComp/heatmapChartUtils.ts @@ -13,6 +13,7 @@ import { calcXYConfig } from "comps/chartComp/chartConfigs/cartesianAxisConfig"; import Big from "big.js"; import { googleMapsApiUrl } from "../chartComp/chartConfigs/chartUrls"; import {chartStyleWrapper, styleWrapper} from "../../util/styleWrapper"; +import { mergeCartesianAxis } from "../../util/echartsThemeUtils"; import parseBackground from "../../util/gradientBackgroundColor"; export function transformData( @@ -169,26 +170,36 @@ export function getEchartsConfig( ...styleWrapper(props?.visualMapStyle, theme?.visualMapStyle, 13), } }, - xAxis: { - type: "category", - data: props?.echartsData?.xAxis || props?.echartsOption && props?.echartsOption.xAxis, - axisLabel: { - ...styleWrapper(props?.xAxisStyle, theme?.xAxisStyle, 13), + xAxis: mergeCartesianAxis( + theme, + "category", + { + type: "category", + data: props?.echartsData?.xAxis || props?.echartsOption && props?.echartsOption.xAxis, }, - splitArea: { - show: props?.xAxisVisibility + props?.xAxisStyle, + 13, + { + splitArea: { + show: props?.xAxisVisibility + } } - }, - yAxis: { - type: "category", - data: props?.echartsData?.yAxis || props?.echartsOption && props?.echartsOption.yAxis, - axisLabel: { - ...styleWrapper(props?.yAxisStyle, theme?.yAxisStyle, 13), + ), + yAxis: mergeCartesianAxis( + theme, + "category", + { + type: "category", + data: props?.echartsData?.yAxis || props?.echartsOption && props?.echartsOption.yAxis, }, - splitArea: { - show: props?.yAxisVisibility + props?.yAxisStyle, + 13, + { + splitArea: { + show: props?.yAxisVisibility + } } - }, + ), series: [ { name: 'Heatmap', diff --git a/client/packages/lowcoder-comps/src/comps/lineChartComp/lineChartUtils.ts b/client/packages/lowcoder-comps/src/comps/lineChartComp/lineChartUtils.ts index 3dfb3769ef..91f576e3fd 100644 --- a/client/packages/lowcoder-comps/src/comps/lineChartComp/lineChartUtils.ts +++ b/client/packages/lowcoder-comps/src/comps/lineChartComp/lineChartUtils.ts @@ -16,6 +16,7 @@ import opacityToHex from "../../util/opacityToHex"; import parseBackground from "../../util/gradientBackgroundColor"; import {ba, s} from "@fullcalendar/core/internal-common"; import {chartStyleWrapper, styleWrapper} from "../../util/styleWrapper"; +import { mergeCartesianAxis } from "../../util/echartsThemeUtils"; export function transformData( originData: JSONObject[], @@ -302,22 +303,27 @@ export function getEchartsConfig( ); config = { ...config, + xAxis: mergeCartesianAxis( + theme, + finalXyConfig.xConfig.type, + finalXyConfig.xConfig, + props?.xAxisStyle, + 11, + { + data: finalXyConfig.xConfig.type === "category" && (props.xAxisData as []).length!==0?props?.xAxisData:transformedData.map((i: any) => i[props.xAxisKey]), + } + ), // @ts-ignore - xAxis: { - ...finalXyConfig.xConfig, - axisLabel: { - ...styleWrapper(props?.xAxisStyle, theme?.xAxisStyle, 11) - }, - data: finalXyConfig.xConfig.type === "category" && (props.xAxisData as []).length!==0?props?.xAxisData:transformedData.map((i: any) => i[props.xAxisKey]), - }, - // @ts-ignore - yAxis: { - ...finalXyConfig.yConfig, - axisLabel: { - ...styleWrapper(props?.yAxisStyle, theme?.yAxisStyle, 11) - }, - data: finalXyConfig.yConfig.type === "category" && (props.xAxisData as []).length!==0?props?.xAxisData:transformedData.map((i: any) => i[props.xAxisKey]), - }, + yAxis: mergeCartesianAxis( + theme, + finalXyConfig.yConfig.type, + finalXyConfig.yConfig, + props?.yAxisStyle, + 11, + { + data: finalXyConfig.yConfig.type === "category" && (props.xAxisData as []).length!==0?props?.xAxisData:transformedData.map((i: any) => i[props.xAxisKey]), + } + ), }; if(props.chartConfig.race) { diff --git a/client/packages/lowcoder-comps/src/comps/scatterChartComp/scatterChartUtils.ts b/client/packages/lowcoder-comps/src/comps/scatterChartComp/scatterChartUtils.ts index f5e9bdd4be..3d2affae3b 100644 --- a/client/packages/lowcoder-comps/src/comps/scatterChartComp/scatterChartUtils.ts +++ b/client/packages/lowcoder-comps/src/comps/scatterChartComp/scatterChartUtils.ts @@ -15,6 +15,7 @@ import opacityToHex from "../../util/opacityToHex"; import parseBackground from "../../util/gradientBackgroundColor"; import {ba, s} from "@fullcalendar/core/internal-common"; import {chartStyleWrapper, styleWrapper} from "../../util/styleWrapper"; +import { mergeCartesianAxis } from "../../util/echartsThemeUtils"; export function transformData( originData: JSONObject[], @@ -179,25 +180,29 @@ export function getEchartsConfig( ...gridPos, containLabel: true, }, - xAxis: { - type: "category", - boundaryGap: props.chartConfig.boundaryGap, - splitLine: { - show: !props.chartConfig.boundaryGap, + xAxis: mergeCartesianAxis( + theme, + "category", + { + type: "category", + boundaryGap: props.chartConfig.boundaryGap, + splitLine: { + show: !props.chartConfig.boundaryGap, + }, + axisLine: { + show: props.chartConfig.boundaryGap, + }, }, - axisLine: { - show: props.chartConfig.boundaryGap, + props?.xAxisStyle + ), + yAxis: mergeCartesianAxis( + theme, + "category", + { + type: "category", }, - axisLabel: { - ...styleWrapper(props?.xAxisStyle, theme?.xAxisStyle, 11) - } - }, - yAxis: { - type: "category", - axisLabel: { - ...styleWrapper(props?.yAxisStyle, theme?.yAxisStyle, 11) - } - }, + props?.yAxisStyle + ), }; if (props.data.length <= 0) { diff --git a/client/packages/lowcoder-comps/src/util/echartsThemeUtils.ts b/client/packages/lowcoder-comps/src/util/echartsThemeUtils.ts new file mode 100644 index 0000000000..cf4a141aa9 --- /dev/null +++ b/client/packages/lowcoder-comps/src/util/echartsThemeUtils.ts @@ -0,0 +1,94 @@ +import { i18n } from "lowcoder-core"; +import { styleWrapper } from "./styleWrapper"; + +const AXIS_THEME_KEY: Record = { + value: "valueAxis", + category: "categoryAxis", + time: "timeAxis", + log: "logAxis", +}; + +/** Workspace theme JSON from Settings → Themes → eCharts Definition */ +export type EChartsThemeJson = Record; + +export function getThemeAxisDefaults(theme: EChartsThemeJson | undefined, axisType?: string) { + const key = AXIS_THEME_KEY[axisType || "value"] || "valueAxis"; + return (theme?.[key] as Record | undefined) ?? {}; +} + +function createCompactAxisFormatter() { + const numberFormat = new Intl.NumberFormat(i18n.locales, { notation: "compact" }); + return (value: string | number) => + typeof value === "number" ? numberFormat.format(value) : String(value); +} + +function isValueOrLogAxis(axisType?: string) { + return axisType === "value" || axisType === "log"; +} + +/** + * Merge axisLabel in priority order: + * 1. Workspace theme (eCharts Definition) + * 2. Component layout (rotate, interval, etc. from calcXYConfig) + * 3. Per-chart Properties panel styles (xAxisStyle / yAxisStyle) + * 4. formatter: user → theme → compact fallback (value/log only) + */ +export function mergeAxisLabel( + theme: EChartsThemeJson | undefined, + axisType: string | undefined, + axisConfigAxisLabel: Record | undefined, + componentStyle: Record | undefined, + defaultFontSize = 11 +) { + const themeAxisLabel = (getThemeAxisDefaults(theme, axisType).axisLabel ?? {}) as Record< + string, + unknown + >; + const { formatter: userFormatter, ...layout } = axisConfigAxisLabel ?? {}; + + const axisLabel: Record = { + ...themeAxisLabel, + ...layout, + ...styleWrapper( + componentStyle, + undefined, + defaultFontSize, + (themeAxisLabel.color as string | undefined) ?? "#000000" + ), + }; + + if (userFormatter) { + axisLabel.formatter = userFormatter; + } else if (axisLabel.formatter == null && isValueOrLogAxis(axisType)) { + axisLabel.formatter = createCompactAxisFormatter(); + } + + return axisLabel; +} + +/** + * Build a cartesian xAxis/yAxis option from: + * - component axis config (type, name, data, layout from calcXYConfig) + * - per-chart Properties panel label styles + * - formatter priority (user > theme > compact fallback) + * + * Note: axisLine, splitLine, axisTick, etc. from the workspace theme are + * applied automatically by ECharts via the `theme` prop on ReactECharts. + * We only handle axisLabel here because styleWrapper needs the theme color + * default, and the formatter priority logic is Lowcoder-specific. + */ +export function mergeCartesianAxis( + theme: EChartsThemeJson | undefined, + axisType: string | undefined, + axisConfig: Record, + componentStyle: Record | undefined, + defaultFontSize = 11, + extra: Record = {} +) { + const { axisLabel: configAxisLabel, ...axisConfigRest } = axisConfig; + return { + ...axisConfigRest, + axisLabel: mergeAxisLabel(theme, axisType, configAxisLabel as Record, componentStyle, defaultFontSize), + ...extra, + }; +}