From b0356c8f0574b43243ac099c580a634b1a26c3d3 Mon Sep 17 00:00:00 2001 From: jianneng-fit2cloud Date: Mon, 25 May 2026 14:29:00 +0800 Subject: [PATCH 1/3] =?UTF-8?q?fix(=E5=9B=BE=E8=A1=A8):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E6=9F=B1=E6=9D=A1=E5=9B=BE=E7=A9=BA=E5=80=BC=E5=A4=84?= =?UTF-8?q?=E7=90=86=E4=B8=8D=E7=94=9F=E6=95=88=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/js/panel/charts/g2/bar/bar.ts | 20 +- .../charts/g2/bar/percentage-stack-bar.ts | 49 ++++- .../charts/g2/bar/percentage-stack-helper.ts | 196 ++++++++++++++++++ .../g2/bar/percentage-stack-horizontal-bar.ts | 64 +++++- .../js/panel/charts/g2/bar/stack-bar.ts | 2 - .../charts/g2/bar/stack-horizontal-bar.ts | 11 +- 6 files changed, 317 insertions(+), 25 deletions(-) create mode 100644 core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/percentage-stack-helper.ts diff --git a/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/bar.ts b/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/bar.ts index 4df495ecc9..4248b375dc 100644 --- a/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/bar.ts +++ b/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/bar.ts @@ -25,6 +25,7 @@ import { } from '@/views/chart/components/editor/util/chart' import { createTooltipWrapper, + handleEmptyDataStrategy, tooltipCss, tooltipMaxHeight, Transform, @@ -182,6 +183,9 @@ export class Bar extends G2ChartView { }, ...position, formatter: (value, data) => { + if (data.value === null || data.value === undefined) { + return '' + } if (data.extremum && showExtremumIds.includes(data.quotaList?.[0]?.id)) { return '' } @@ -247,7 +251,10 @@ export class Bar extends G2ChartView { const head = originalItems[0] tooltipItems.forEach(item => { const formatter = formatterMap[item.quotaList[0].id] ?? yAxis[0] - const value = valueFormatter(item.value, formatter.formatterCfg) + const value = + item.value === null || item.value === undefined + ? '' + : valueFormatter(item.value, formatter.formatterCfg) const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName @@ -256,7 +263,10 @@ export class Bar extends G2ChartView { head.dynamicTooltipValue?.forEach(item => { const formatter = formatterMap[item.fieldId] if (formatter) { - const value = valueFormatter(parseFloat(item.value), formatter.formatterCfg) + const value = + item.value === null || item.value === undefined + ? '' + : valueFormatter(parseFloat(item.value), formatter.formatterCfg) const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName @@ -832,9 +842,15 @@ export class Bar extends G2ChartView { return options } + protected configEmptyDataStrategy(chart: Chart, options: ViewSpec): ViewSpec { + handleEmptyDataStrategy(chart, options) + return options + } + protected setupOptions(chart: Chart, options: ViewSpec): ViewSpec { return flow( this.configTheme, + this.configEmptyDataStrategy, this.configBasicStyle, this.configColor, this.configLabel, diff --git a/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/percentage-stack-bar.ts b/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/percentage-stack-bar.ts index 30bb32f74c..5bbfb562e0 100644 --- a/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/percentage-stack-bar.ts +++ b/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/percentage-stack-bar.ts @@ -7,12 +7,23 @@ import { ViewSpec } from '@/views/chart/components/js/panel/charts/g2/bar/barUtil' import { GroupStackBar } from '@/views/chart/components/js/panel/charts/g2/bar/group-stack-bar' +import type { G2DrawOptions } from '@/views/chart/components/js/panel/types/impl/g2' import { toLinearGradient, TOOLTIP_ITEM_TPL, TOOLTIP_TITLE_TPL } from '@/views/chart/components/js/panel/common/common_antv' +import type { Chart as G2Column } from '@antv/g2' import { isEmpty } from 'lodash-es' +import { + configPercentageStackEmptyAnchorStyle, + configPercentageStackEmptyAnchorTooltipGuard, + configPercentageStackEmptyDataStrategy, + filterPercentageStackTooltipItems, + formatPercentageStackRatio, + getPercentageStackFieldTotal, + shouldHidePercentageStackLabelValue +} from '@/views/chart/components/js/panel/charts/g2/bar/percentage-stack-helper' /** * 百分比堆叠柱状图 @@ -24,6 +35,24 @@ export class PercentageStackBar extends GroupStackBar { 'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'show', 'carousel'] } + async drawChart(drawOptions: G2DrawOptions): Promise { + const newChart = await super.drawChart(drawOptions) + if (newChart) { + configPercentageStackEmptyAnchorTooltipGuard(newChart) + } + return newChart + } + + protected configEmptyDataStrategy(chart: Chart, options: ViewSpec): ViewSpec { + return configPercentageStackEmptyDataStrategy(chart, options, () => { + super.configEmptyDataStrategy(chart, options) + }) + } + + protected configEmptyAnchorStyle(_chart: Chart, options: ViewSpec): ViewSpec { + return configPercentageStackEmptyAnchorStyle(options) + } + protected configLabel(chart: Chart, options: ViewSpec): ViewSpec { const customAttr = parseJson(chart.customAttr) const { label: labelAttr } = customAttr @@ -48,11 +77,9 @@ export class PercentageStackBar extends GroupStackBar { ...position, formatter: (value, _data, _, o) => { // 计算与当前数据相同 field 的 value 总和 - const sum = - o?.reduce( - (acc, item) => (item.field === _data.field ? acc + (item.value || 0) : acc), - 0 - ) || 1 + const sum = getPercentageStackFieldTotal(o, _data.field) + if (shouldHidePercentageStackLabelValue(value, _data, sum)) return '' + if (!sum) return `${(0).toFixed(labelAttr.reserveDecimalCount)}%` // 返回百分比格式化结果 return `${((value / sum) * 100).toFixed(labelAttr.reserveDecimalCount)}%` }, @@ -93,17 +120,20 @@ export class PercentageStackBar extends GroupStackBar { position: 'top-right', render: (_, { title, items: originalItems }) => { const titleHtml = TOOLTIP_TITLE_TPL.replace('{title}', title) - const tooltipItems = originalItems + // 锚点只负责鼠标命中,不应出现在 tooltip 明细里。 + const tooltipItems = filterPercentageStackTooltipItems(originalItems) + if (!tooltipItems.length) return '' const sum = tooltipItems?.reduce( (acc, { value = 0 }: { value: number }) => acc + value, 0 ) const result = [] tooltipItems.forEach(item => { - const itemValue = item.value ? (item.value as number) : 0 - const value = `${((itemValue / sum) * 100).toFixed( + const value = formatPercentageStackRatio( + item.value, + sum, tooltip.tooltipFormatter.decimalCount - )}%` + ) const name = `${isEmpty(item.category) ? item.field : item.category}${ item.group ? '-' + item.group : '' }` @@ -146,6 +176,7 @@ export class PercentageStackBar extends GroupStackBar { this.configYAxis, this.configAnalyse, this.configBarConditions, + this.configEmptyAnchorStyle, this.configSlider )(chart, options, {}, this) } diff --git a/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/percentage-stack-helper.ts b/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/percentage-stack-helper.ts new file mode 100644 index 0000000000..7b0e738425 --- /dev/null +++ b/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/percentage-stack-helper.ts @@ -0,0 +1,196 @@ +import { parseJson } from '@/views/chart/components/js/util' +import type { ViewSpec } from '@/views/chart/components/js/panel/charts/g2/bar/barUtil' +import type { Chart as G2Column } from '@antv/g2' + +// 空值锚点只用于保留空维度的命中区域,不参与图例、标签和 tooltip 展示。 +export const PERCENTAGE_STACK_EMPTY_ANCHOR_FIELD = '__DE_PERCENTAGE_STACK_EMPTY_ANCHOR__' +const PERCENTAGE_STACK_EMPTY_ANCHOR_VALUE = 1e-12 + +export function isPercentageStackEmptyAnchor(item) { + return !!item?.[PERCENTAGE_STACK_EMPTY_ANCHOR_FIELD] +} + +export function configPercentageStackEmptyAnchorTooltipGuard(newChart: G2Column) { + newChart.on('tooltip:show', event => { + // 鼠标只命中空值锚点时,隐藏 tooltip,避免展示一条假的空数据提示。 + if (isOnlyPercentageStackEmptyAnchorTooltip(event)) { + newChart.emit('tooltip:hide') + } + }) +} + +export function configPercentageStackEmptyDataStrategy( + chart: Chart, + options: ViewSpec, + handleEmptyDataStrategy: () => void +): ViewSpec { + const strategy = parseJson(chart.senior).functionCfg.emptyDataStrategy + const data = getPercentageStackOptionsData(options) + // 先记录原始维度顺序和示例数据,空值处理后才能把锚点补回正确位置。 + const anchorContext = buildEmptyAnchorContext(data) + handleEmptyDataStrategy() + // 隐藏空值策略的语义是删除空维度,不补锚点,避免空柱子继续占位。 + if (strategy === 'ignoreData') { + return options + } + appendEmptyAnchors(getPercentageStackOptionsData(options), anchorContext) + return options +} + +export function configPercentageStackEmptyAnchorStyle(options: ViewSpec): ViewSpec { + const { children } = options + const child = children[0] + const style = child.style ?? {} + const { fill, fillOpacity, strokeOpacity } = style + + return { + ...options, + children: [ + { + ...child, + style: { + ...style, + fill: data => { + if (isPercentageStackEmptyAnchor(data)) return 'rgba(0,0,0,0)' + return typeof fill === 'function' ? fill(data) : fill ?? data.color + }, + fillOpacity: data => { + // 保留极低透明度,让 G2 仍能为锚点生成可命中的 interval。 + if (isPercentageStackEmptyAnchor(data)) return 0.001 + return typeof fillOpacity === 'function' ? fillOpacity(data) : fillOpacity + }, + strokeOpacity: data => { + if (isPercentageStackEmptyAnchor(data)) return 0 + return typeof strokeOpacity === 'function' ? strokeOpacity(data) : strokeOpacity + } + } + }, + ...children.slice(1) + ] + } +} + +export function getPercentageStackOptionsData(options: ViewSpec): any[] { + const data = options.children?.[0]?.data ?? options.data + if (Array.isArray(data)) return data + if (Array.isArray(data?.value)) return data.value + return [] +} + +export function getPercentageStackFieldTotal(dataItems: any[], field) { + return ( + dataItems?.reduce( + (acc, item) => + item?.field === field && !isPercentageStackEmptyAnchor(item) + ? acc + (Number(item.value) || 0) + : acc, + 0 + ) || 0 + ) +} + +export function getPercentageStackZeroTotalFields(data: any[]) { + const fieldTotalMap = new Map() + data?.forEach(item => { + if (isPercentageStackEmptyAnchor(item)) return + fieldTotalMap.set( + item?.field, + (fieldTotalMap.get(item?.field) || 0) + (Number(item.value) || 0) + ) + }) + return new Set([...fieldTotalMap].filter(([, total]) => total === 0).map(([field]) => field)) +} + +export function shouldHidePercentageStackLabelValue(value, item, fieldTotal) { + const numberValue = Number(value) + if (isPercentageStackEmptyAnchor(item) || !Number.isFinite(numberValue)) { + return true + } + return numberValue === 0 && fieldTotal > 0 +} + +export function filterPercentageStackTooltipItems(items: any[] = []) { + return items?.filter(item => !isPercentageStackEmptyAnchor(item)) ?? [] +} + +export function formatPercentageStackRatio(value, total, decimalCount) { + const itemValue = value ? (value as number) : 0 + return `${total ? ((itemValue / total) * 100).toFixed(decimalCount) : (0).toFixed(decimalCount)}%` +} + +function isOnlyPercentageStackEmptyAnchorTooltip(event) { + const items = event?.data?.items + return ( + Array.isArray(items) && + items.length > 0 && + items.every(item => isPercentageStackEmptyAnchor(item)) + ) +} + +function buildEmptyAnchorContext(data: any[]) { + const fields: any[] = [] + const sampleByField = new Map() + const indexByField = new Map() + let fallbackSample + + data?.forEach((item, index) => { + if (item?.field === undefined) return + if (!sampleByField.has(item.field)) { + fields.push(item.field) + sampleByField.set(item.field, item) + indexByField.set(item.field, index) + } + if (!fallbackSample && item?.category !== undefined) { + fallbackSample = item + } + }) + + return { fields, sampleByField, indexByField, fallbackSample } +} + +function appendEmptyAnchors(data: any[], anchorContext) { + if (!data?.length && !anchorContext?.fields?.length) return + + anchorContext.fields.forEach(field => { + // 仅对全空或全 0 的维度补一个极小值锚点,避免 normalizeY 出现无可命中的空维度。 + if (!needsEmptyAnchor(data, field)) return + const sample = anchorContext.sampleByField.get(field) ?? anchorContext.fallbackSample ?? {} + data.splice(getEmptyAnchorInsertIndex(data, field, anchorContext), 0, { + ...sample, + field, + category: sample.category ?? anchorContext.fallbackSample?.category, + group: sample.group ?? anchorContext.fallbackSample?.group, + quotaList: sample.quotaList ?? anchorContext.fallbackSample?.quotaList, + value: PERCENTAGE_STACK_EMPTY_ANCHOR_VALUE, + [PERCENTAGE_STACK_EMPTY_ANCHOR_FIELD]: true + }) + }) +} + +function getEmptyAnchorInsertIndex(data: any[], field, anchorContext) { + // 若该维度还有部分真实数据,锚点跟随真实数据之后,避免打散同一维度的数据。 + const sameFieldLastIndex = data.reduce( + (lastIndex, item, index) => (item?.field === field ? index : lastIndex), + -1 + ) + if (sameFieldLastIndex >= 0) { + return sameFieldLastIndex + 1 + } + + // 若该维度已被空值策略删光,按空值处理前的原始维度顺序插回。 + const fieldIndex = anchorContext.indexByField.get(field) + const nextIndex = data.findIndex(item => { + const itemIndex = anchorContext.indexByField.get(item?.field) + return itemIndex !== undefined && itemIndex > fieldIndex + }) + return nextIndex === -1 ? data.length : nextIndex +} + +function needsEmptyAnchor(data: any[], field) { + const fieldData = data.filter( + item => item?.field === field && !isPercentageStackEmptyAnchor(item) + ) + if (!fieldData.length) return true + const total = fieldData.reduce((sum, item) => sum + (Number(item.value) || 0), 0) + return total === 0 +} diff --git a/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/percentage-stack-horizontal-bar.ts b/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/percentage-stack-horizontal-bar.ts index aecf9cfb48..37ec58621d 100644 --- a/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/percentage-stack-horizontal-bar.ts +++ b/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/percentage-stack-horizontal-bar.ts @@ -12,6 +12,19 @@ import { } from '@/views/chart/components/js/panel/common/common_antv' import { isEmpty } from 'lodash-es' import { HorizontalStackBar } from '@/views/chart/components/js/panel/charts/g2/bar/stack-horizontal-bar' +import type { G2DrawOptions } from '@/views/chart/components/js/panel/types/impl/g2' +import type { Chart as G2Column } from '@antv/g2' +import { + configPercentageStackEmptyAnchorStyle, + configPercentageStackEmptyAnchorTooltipGuard, + configPercentageStackEmptyDataStrategy, + filterPercentageStackTooltipItems, + formatPercentageStackRatio, + getPercentageStackFieldTotal, + getPercentageStackOptionsData, + getPercentageStackZeroTotalFields, + shouldHidePercentageStackLabelValue +} from '@/views/chart/components/js/panel/charts/g2/bar/percentage-stack-helper' /** * 百分比条形图 @@ -23,17 +36,39 @@ export class PercentageStackBar extends HorizontalStackBar { 'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'show'] } + async drawChart(drawOptions: G2DrawOptions): Promise { + const newChart = await super.drawChart(drawOptions) + if (newChart) { + configPercentageStackEmptyAnchorTooltipGuard(newChart) + } + return newChart + } + + protected configEmptyDataStrategy(chart: Chart, options: ViewSpec): ViewSpec { + return configPercentageStackEmptyDataStrategy(chart, options, () => { + super.configEmptyDataStrategy(chart, options) + }) + } + + protected configEmptyAnchorStyle(_chart: Chart, options: ViewSpec): ViewSpec { + return configPercentageStackEmptyAnchorStyle(options) + } + protected configLabel(chart: Chart, options: ViewSpec): ViewSpec { const customAttr = parseJson(chart.customAttr) const { label: labelAttr } = customAttr if (!labelAttr.show) return options const { children } = options + const zeroTotalFields = getPercentageStackZeroTotalFields( + getPercentageStackOptionsData(options) + ) + const isZeroTotalField = data => zeroTotalFields.has(data?.field) const position = { position: labelAttr.position === 'middle' ? 'inside' : labelAttr.position, - textAlign: 'center', + textAlign: data => (isZeroTotalField(data) ? 'start' : 'center'), dy: labelAttr.position === 'top' ? -10 : 0, - dx: 0 + dx: data => (isZeroTotalField(data) ? 4 : 0) } const transform = labelAttr.fullDisplay ? {} @@ -47,11 +82,9 @@ export class PercentageStackBar extends HorizontalStackBar { ...position, formatter: (value, _data, _, o) => { // 计算与当前数据相同 field 的 value 总和 - const sum = - o?.reduce( - (acc, item) => (item.field === _data.field ? acc + (item.value || 0) : acc), - 0 - ) || 1 + const sum = getPercentageStackFieldTotal(o, _data.field) + if (shouldHidePercentageStackLabelValue(value, _data, sum)) return '' + if (!sum) return `${(0).toFixed(labelAttr.reserveDecimalCount)}%` // 返回百分比格式化结果 return `${((value / sum) * 100).toFixed(labelAttr.reserveDecimalCount)}%` }, @@ -88,17 +121,20 @@ export class PercentageStackBar extends HorizontalStackBar { position: 'top-right', render: (_, { title, items: originalItems }) => { const titleHtml = TOOLTIP_TITLE_TPL.replace('{title}', title) - const tooltipItems = originalItems + // 锚点只负责鼠标命中,不应出现在 tooltip 明细里。 + const tooltipItems = filterPercentageStackTooltipItems(originalItems) + if (!tooltipItems.length) return '' const sum = tooltipItems?.reduce( (acc, { value = 0 }: { value: number }) => acc + value, 0 ) const result = [] tooltipItems.forEach(item => { - const itemValue = item.value ? (item.value as number) : 0 - const value = `${((itemValue / sum) * 100).toFixed( + const value = formatPercentageStackRatio( + item.value, + sum, tooltip.tooltipFormatter.decimalCount - )}%` + ) const name = `${isEmpty(item.category) ? item.field : item.category}${ item.group ? '-' + item.group : '' }` @@ -138,10 +174,16 @@ export class PercentageStackBar extends HorizontalStackBar { this.configXAxis, this.configYAxis, this.configAnalyse, + this.configEmptyAnchorStyle, this.configSlider )(chart, options, {}, this) } + setupDefaultOptions(chart: ChartObj): ChartObj { + chart.customAttr.label.position = 'middle' + return super.setupDefaultOptions(chart) + } + constructor(name = 'percentage-bar-stack-horizontal') { super(name) this.intervalOptions.encode = { diff --git a/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/stack-bar.ts b/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/stack-bar.ts index bd73d27706..b11ad82d3a 100644 --- a/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/stack-bar.ts +++ b/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/stack-bar.ts @@ -194,8 +194,6 @@ export class StackBar extends Bar { } protected configEmptyDataStrategy(chart: Chart, options: ViewSpec): ViewSpec { - const { data } = options.children[0] - if (!data?.length) return options handleEmptyDataStrategy(chart, options) return options } diff --git a/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/stack-horizontal-bar.ts b/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/stack-horizontal-bar.ts index 9b5dcc46ad..28065b145c 100644 --- a/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/stack-horizontal-bar.ts +++ b/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/stack-horizontal-bar.ts @@ -60,7 +60,13 @@ export class HorizontalStackBar extends HorizontalBar { fill: labelAttr.color, fontSize: labelAttr.fontSize, ...position, - formatter: (value, _data) => valueFormatter(value, labelAttr.labelFormatter), + formatter: (value, _data) => { + debugger + if (value === null || value === undefined) { + return '' + } + return valueFormatter(value, labelAttr.labelFormatter) + }, transform } ] @@ -97,6 +103,9 @@ export class HorizontalStackBar extends HorizontalBar { const tooltipItems = originalItems const result = [] tooltipItems.forEach(item => { + if (item.value === null || item.value === undefined) { + return '' + } const value = valueFormatter(item.value, tooltip.tooltipFormatter) const name = isEmpty(item.category) ? item.field : item.category result.push({ ...item, name, value }) From 2fe8de69fd7af22d5b1fff62becc307146917d9d Mon Sep 17 00:00:00 2001 From: jianneng-fit2cloud Date: Mon, 25 May 2026 14:47:58 +0800 Subject: [PATCH 2/3] =?UTF-8?q?fix(=E5=9B=BE=E8=A1=A8):=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=E6=9D=A1=E5=BD=A2=E5=9B=BE=E8=BE=85=E5=8A=A9=E7=BA=BF?= =?UTF-8?q?-=E6=95=B0=E5=80=BC=E6=A0=BC=E5=BC=8F=E6=B2=A1=E6=9C=89?= =?UTF-8?q?=E4=B8=8E=E6=A8=AA=E8=BD=B4=E7=BB=9F=E4=B8=80=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chart/components/js/panel/charts/g2/bar/bar.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/bar.ts b/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/bar.ts index 4248b375dc..53566dc023 100644 --- a/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/bar.ts +++ b/core/core-frontend/src/views/chart/components/js/panel/charts/g2/bar/bar.ts @@ -526,10 +526,10 @@ export class Bar extends G2ChartView { const { children } = options return { ...options, - children: [...children, ...this.getAssistLineStyle(chart)] + children: [...children, ...this.getAssistLineStyle(chart, options)] } } - protected getAssistLineStyle = (chart: Chart) => { + protected getAssistLineStyle = (chart: Chart, options?: ViewSpec) => { const assistLine = [] const senior = parseJson(chart.senior) if (!senior.assistLineCfg?.enable) { @@ -540,6 +540,8 @@ export class Bar extends G2ChartView { const customStyle = parseJson(chart.customStyle) let axisFormatterCfg, axisExtFormatterCfg const isHorizontalBar = this.name.includes('horizontal') + const axis = options?.children?.[0]?.axis + const valueAxisLabelFormatter = isHorizontalBar ? (axis as any)?.y?.labelFormatter : undefined if (isHorizontalBar) { if (customStyle.xAxis) { const a = JSON.parse(JSON.stringify(customStyle.xAxis)) @@ -580,7 +582,11 @@ export class Bar extends G2ChartView { const value = parseFloat(item.value) const targetFormatter = item.yAxisType === 'left' || !axisExtFormatterCfg ? axisFormatterCfg : axisExtFormatterCfg - const content = item.name + ' : ' + valueFormatter(value, targetFormatter) + const axisFormattedValue = + typeof valueAxisLabelFormatter === 'function' + ? valueAxisLabelFormatter(value) + : valueFormatter(value, targetFormatter) + const content = item.name + ' : ' + axisFormattedValue const fontSize = item.fontSize ? parseInt(item.fontSize + '') : '100%' assistLine.push({ type: 'lineY', From ee330de238cce88b9d94919f61b06c8daab509bb Mon Sep 17 00:00:00 2001 From: jianneng-fit2cloud Date: Mon, 25 May 2026 15:32:40 +0800 Subject: [PATCH 3/3] =?UTF-8?q?fix(=E6=95=A3=E7=82=B9=E5=9B=BE):=20?= =?UTF-8?q?=E4=BC=98=E5=8C=96y=E8=BD=B4=E5=88=BB=E5=BA=A6=E5=92=8C?= =?UTF-8?q?=E6=A0=87=E7=AD=BE=E6=A0=B7=E5=BC=8F=EF=BC=8C=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E6=A0=87=E7=AD=BE=E4=BD=8D=E7=BD=AE=E5=8F=8A=E6=96=87=E6=9C=AC?= =?UTF-8?q?=E5=AF=B9=E9=BD=90=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../js/panel/charts/g2/relation/scatter.ts | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/core/core-frontend/src/views/chart/components/js/panel/charts/g2/relation/scatter.ts b/core/core-frontend/src/views/chart/components/js/panel/charts/g2/relation/scatter.ts index 686cb6c894..03b5c2c8e6 100644 --- a/core/core-frontend/src/views/chart/components/js/panel/charts/g2/relation/scatter.ts +++ b/core/core-frontend/src/views/chart/components/js/panel/charts/g2/relation/scatter.ts @@ -109,6 +109,11 @@ export class Scatter extends G2ChartView { y: 'value', color: 'category' }, + scale: { + y: { + nice: true + } + }, legend: { size: false } @@ -236,14 +241,17 @@ export class Scatter extends G2ChartView { const value = valueFormatter(d.value, label.labelFormatter) return toString(value) }, - position: 'top', + position: 'inside', style: { fill: label.color, fontSize: label.fontSize, - textBaseline: 'bottom', + textAlign: 'center', + textBaseline: 'middle', fillOpacity: 1 }, - transform: label.fullDisplay ? [] : [{ type: 'overlapHide' }, { type: 'exceedAdjust' }] + transform: label.fullDisplay + ? [{ type: 'exceedAdjust' }] + : [{ type: 'exceedAdjust' }, { type: 'overlapHide' }] } ] } @@ -468,6 +476,7 @@ export class Scatter extends G2ChartView { const scaleOpt = { scale: { y: { + nice: false, domainMin: yAxis.axisValue.min, domainMax: yAxis.axisValue.max, tickCount: yAxis.axisValue.splitCount < 2 ? 2 : yAxis.axisValue.splitCount, @@ -483,6 +492,11 @@ export class Scatter extends G2ChartView { } } defaultsDeep(axisOption, scaleOpt) + const result = defaultsDeep(options, axisOption) + if (result.scale?.y) { + result.scale.y.nice = false + } + return result } return defaultsDeep(options, axisOption) }