fix(图表): 优化基础折线图、面积图的提示以及图例显示顺序与指标字段自上而下顺序统一,以及堆叠折线图的显示优化

This commit is contained in:
jianneng-fit2cloud
2026-05-28 11:29:03 +08:00
parent 39fa420d61
commit 55e50c08f3
3 changed files with 148 additions and 7 deletions

View File

@@ -15,7 +15,14 @@ import {
} from '@/views/chart/components/js/util'
import { cloneDeep, defaultsDeep, isEmpty, merge } from 'lodash-es'
import { valueFormatter } from '@/views/chart/components/js/formatter'
import { LINE_AXIS_TYPE, LINE_EDITOR_PROPERTY, LINE_EDITOR_PROPERTY_INNER } from './common'
import {
configStackOrderByYAxis,
configYAxisSeriesLegendDomain,
LINE_AXIS_TYPE,
LINE_EDITOR_PROPERTY,
LINE_EDITOR_PROPERTY_INNER,
sortTooltipItemsByYAxis
} from './common'
import { useI18n } from '@/hooks/web/useI18n'
import { addExtremumText, extremumEvt } from '@/views/chart/components/js/extremumUitl'
import { Chart as G2Chart, G2Spec } from '@antv/g2'
@@ -501,7 +508,7 @@ export class Area extends G2ChartView {
}
}
defaultsDeep(options, tmpLegend)
return options
return configYAxisSeriesLegendDomain(chart, options)
}
protected configAssistLine(chart: Chart, options: G2Spec): G2Spec {
@@ -616,7 +623,7 @@ export class Area extends G2ChartView {
}
const result = []
const head = originalItems[0]
tooltipItems.forEach(item => {
sortTooltipItemsByYAxis(chart, tooltipItems).forEach(item => {
if (item.value === null || item.value === undefined) {
return
}
@@ -855,6 +862,10 @@ export class StackArea extends Area {
return options
}
protected configLegend(chart: Chart, options: G2Spec): G2Spec {
return super.configLegend(chart, configStackOrderByYAxis(chart, options))
}
protected configTooltip(chart: Chart, options: G2Spec): G2Spec {
const customAttr: DeepPartial<ChartAttr> = parseJson(chart.customAttr)
const tooltipAttr = customAttr.tooltip
@@ -874,7 +885,7 @@ export class StackArea extends Area {
render: (e, { title, items }) => {
const titleHtml = TOOLTIP_TITLE_TPL.replace('{title}', title)
const result = []
items.forEach(item => {
sortTooltipItemsByYAxis(chart, items).forEach(item => {
if (item.value === null || item.value === undefined) {
return
}

View File

@@ -1,3 +1,5 @@
import type { G2Spec } from '@antv/g2'
export const LINE_EDITOR_PROPERTY: EditorProperty[] = [
'background-overall-component',
'border-style',
@@ -72,3 +74,125 @@ export const LINE_AXIS_TYPE: AxisType[] = [
'extLabel',
'extTooltip'
]
const Y_AXIS_SERIES_ORDER_NOT_FOUND = Number.MAX_SAFE_INTEGER
/**
* 只有系列来自值轴指标时才按指标顺序处理;有分组/堆叠维度时,系列来自维度值,保留原逻辑
*/
export const isYAxisSeriesChart = (chart: Chart) => {
return !!chart.yAxis?.length && !chart.xAxisExt?.length && !chart.extStack?.length
}
/**
* 指标系列在图表数据里的名称来自字段展示名,未设置展示名时使用字段名
*/
export const getYAxisSeriesName = axis => axis.chartShowName || axis.name
/**
* 为 legend 生成值轴指标顺序的 color domain同时保留数据里未匹配到的新系列
*/
export const getYAxisSeriesDomain = (chart: Chart, data: any[] = []) => {
const domain = []
chart.yAxis?.forEach(axis => {
const name = getYAxisSeriesName(axis)
if (name && !domain.includes(name)) {
domain.push(name)
}
})
data.forEach(item => {
if (item.category && !domain.includes(item.category)) {
domain.push(item.category)
}
})
return domain
}
/**
* 建立指标 id/显示名到字段下标的映射,供 tooltip 和堆叠层级排序复用
*/
export const getYAxisOrderMap = (chart: Chart) => {
const orderMap = new Map<string, number>()
chart.yAxis?.forEach((axis, index) => {
orderMap.set(axis.id, index)
const name = getYAxisSeriesName(axis)
if (name) {
orderMap.set(name, index)
}
})
return orderMap
}
/**
* 根据指标字段顺序获取当前系列排序值,未命中时放到最后并保持原相对顺序
*/
export const getYAxisSeriesOrder = (orderMap: Map<string, number>, item) => {
return (
orderMap.get(item.quotaList?.[0]?.id) ??
orderMap.get(item.category) ??
Y_AXIS_SERIES_ORDER_NOT_FOUND
)
}
/**
* 对 tooltip items 按右侧指标字段自上而下排序
*/
export const sortTooltipItemsByYAxis = (chart: Chart, items: any[]) => {
if (!isYAxisSeriesChart(chart)) {
return items
}
const orderMap = getYAxisOrderMap(chart)
return items
.map((item, index) => ({
item,
index,
order: getYAxisSeriesOrder(orderMap, item)
}))
.sort((a, b) => a.order - b.order || a.index - b.index)
.map(({ item }) => item)
}
/**
* 对 legend 的 color domain 按右侧指标字段自上而下排序,不覆盖已有颜色映射等样式配置
*/
export const configYAxisSeriesLegendDomain = (chart: Chart, options: G2Spec) => {
if (!isYAxisSeriesChart(chart)) {
return options
}
const domain = getYAxisSeriesDomain(chart, options.data?.value)
if (!domain.length) {
return options
}
const scale = options.scale ?? {}
options.scale = {
...scale,
color: {
...(scale.color ?? {}),
domain
}
}
return options
}
/**
* G2 正值堆叠是从下往上累加,堆叠折线需要反向使用指标下标来实现视觉自上而下对齐
*/
export const configStackOrderByYAxis = (chart: Chart, options: G2Spec) => {
if (!isYAxisSeriesChart(chart)) {
return options
}
const orderMap = getYAxisOrderMap(chart)
options.transform = (options.transform ?? []).map(transform => {
if (transform.type !== 'stackY') {
return transform
}
return {
...transform,
orderBy: item => {
const order = getYAxisSeriesOrder(orderMap, item)
return order === Y_AXIS_SERIES_ORDER_NOT_FOUND ? order : -order
}
}
})
return options
}

View File

@@ -14,7 +14,13 @@ import {
} from '@/views/chart/components/js/util'
import { cloneDeep, defaultsDeep, isEmpty, merge } from 'lodash-es'
import { valueFormatter } from '@/views/chart/components/js/formatter'
import { LINE_AXIS_TYPE, LINE_EDITOR_PROPERTY, LINE_EDITOR_PROPERTY_INNER } from './common'
import {
configYAxisSeriesLegendDomain,
LINE_AXIS_TYPE,
LINE_EDITOR_PROPERTY,
LINE_EDITOR_PROPERTY_INNER,
sortTooltipItemsByYAxis
} from './common'
import { useI18n } from '@/hooks/web/useI18n'
import { Chart as G2Chart, G2Spec } from '@antv/g2'
import { DEFAULT_YAXIS_STYLE } from '@/views/chart/components/editor/util/chart'
@@ -566,7 +572,7 @@ export class Line extends G2ChartView {
defaultsDeep(options, scaleOpt)
}
}
return options
return configYAxisSeriesLegendDomain(chart, options)
}
protected configAssistLine(chart: Chart, options: G2Spec): G2Spec {
@@ -683,7 +689,7 @@ export class Line extends G2ChartView {
}
const result = []
const head = originalItems[0]
tooltipItems.forEach(item => {
sortTooltipItemsByYAxis(chart, tooltipItems).forEach(item => {
if (item.value === null || item.value === undefined) {
return
}