Merge remote-tracking branch 'origin/dev-v3' into dev-v3

This commit is contained in:
wangjiahao
2026-05-28 16:12:00 +08:00
7 changed files with 249 additions and 28 deletions

View File

@@ -206,6 +206,9 @@ const showSort = computed(() => {
return !isChartMix || isDimensionType
})
const showSortPriority = computed(() => {
if (props.chart.type === 'line' && props.type === 'dimensionExt') {
return false
}
if (props.chart.type.includes('chart-mix')) {
return false
}

View File

@@ -40,6 +40,8 @@ const getRgbaColorLastRgba = (rgbaString: string) => {
return lastRGBA
}
const EXTREMUM_LABEL_MARK_TYPES = ['point', 'interval']
/**
* 判断图表类型是否支持最值标注(极值标签)
* @param chart - 图表配置对象
@@ -94,7 +96,7 @@ export const extremumEvt = (
const chartData = options.children ? options.children : [options]
// 遍历所有 series为标签注入 HTML 和样式
chartData
.filter(item => item.labels?.length)
.filter(item => item.labels?.length && EXTREMUM_LABEL_MARK_TYPES.includes(item.type))
.forEach(item => {
item.labels.forEach(label => {
const oldPosition = label.position || 'top'

View File

@@ -75,7 +75,7 @@ export class StackBar extends Bar {
fill: labelAttr.color,
fontSize: labelAttr.fontSize,
...position,
formatter: (value, _data) => valueFormatter(value, labelAttr.labelFormatter),
formatter: value => valueFormatter(value, labelAttr.labelFormatter),
...transform
})
}
@@ -83,19 +83,38 @@ export class StackBar extends Bar {
if (labelAttr.showTotal) {
const formatterCfg = labelAttr.labelFormatter ?? formatterItem
const groupedData = groupBy(options.data, 'field')
for (const [key, values] of Object.entries(groupedData)) {
const totalData = Object.entries(groupedData).map(([key, values]) => {
const total = values.reduce((a, b) => a + b.value, 0)
const value = valueFormatter(total, formatterCfg)
return {
field: key,
value: total,
totalLabel: valueFormatter(total, formatterCfg)
}
})
if (totalData.length) {
children.push({
type: 'text',
data: [key, total],
style: {
text: value,
textAlign: 'center',
dy: -10,
fill: labelAttr.color,
fontSize: labelAttr.fontSize
type: 'point',
data: totalData,
encode: {
x: 'field',
y: 'value'
},
style: {
opacity: 0
},
labels: [
{
text: 'totalLabel',
fillOpacity: 1,
fill: labelAttr.color,
fontSize: labelAttr.fontSize,
position: 'top',
dx: 0,
dy: -10,
...transform,
textAlign: 'center'
}
],
tooltip: false
})
}

View File

@@ -1,4 +1,7 @@
import { BAR_EDITOR_PROPERTY } from '@/views/chart/components/js/panel/charts/g2/bar/common'
import {
BAR_EDITOR_PROPERTY,
BAR_EDITOR_PROPERTY_INNER
} from '@/views/chart/components/js/panel/charts/g2/bar/common'
import { flow, parseJson } from '@/views/chart/components/js/util'
import {
createTooltipWrapper,
@@ -11,9 +14,9 @@ import {
TOOLTIP_ITEM_TPL,
TOOLTIP_TITLE_TPL
} from '@/views/chart/components/js/panel/common/common_antv'
import { valueFormatter } from '@/views/chart/components/js/formatter'
import { formatterItem, valueFormatter } from '@/views/chart/components/js/formatter'
import { HorizontalBar } from '@/views/chart/components/js/panel/charts/g2/bar/horizontal-bar'
import { isEmpty } from 'lodash-es'
import { groupBy, isEmpty } from 'lodash-es'
const { t } = useI18n()
@@ -33,7 +36,15 @@ export class HorizontalStackBar extends HorizontalBar {
}
propertyInner = {
...this['propertyInner'],
'label-selector': ['color', 'fontSize', 'hPosition', 'labelFormatter'],
'label-selector': [
...BAR_EDITOR_PROPERTY_INNER['label-selector'],
'hPosition',
'showTotal',
'totalColor',
'totalFontSize',
'totalFormatter',
'showStackQuota'
],
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'tooltipFormatter', 'show']
}
@@ -53,23 +64,64 @@ export class HorizontalStackBar extends HorizontalBar {
...(labelAttr.fullDisplay ? [] : [{ type: 'overlapHide' }])
]
const labels = [
{
const labels = []
if (labelAttr.showStackQuota ?? true) {
labels.push({
text: 'value',
fillOpacity: 1,
fill: labelAttr.color,
fontSize: labelAttr.fontSize,
...position,
formatter: (value, _data) => {
debugger
formatter: value => {
if (value === null || value === undefined) {
return ''
}
return valueFormatter(value, labelAttr.labelFormatter)
},
transform
})
}
if (labelAttr.showTotal) {
const formatterCfg = labelAttr.labelFormatter ?? formatterItem
const groupedData = groupBy(options.data, 'field')
const totalData = Object.entries(groupedData).map(([key, values]) => {
const total = values.reduce((a, b) => a + b.value, 0)
return {
field: key,
value: total,
totalLabel: valueFormatter(total, formatterCfg)
}
})
if (totalData.length) {
children.push({
type: 'point',
data: totalData,
encode: {
x: 'field',
y: 'value'
},
coordinate: { transform: [{ type: 'transpose' }] },
style: {
opacity: 0
},
labels: [
{
text: 'totalLabel',
fillOpacity: 1,
fill: labelAttr.color,
fontSize: labelAttr.fontSize,
position: 'right',
dx: 4,
dy: 0,
transform,
textAlign: 'start'
}
],
tooltip: false
})
}
]
}
return {
...options,

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'
@@ -383,6 +390,7 @@ export class Area extends G2ChartView {
lineLineDash,
label: xAxis.axisLabel.show,
labelFill: xAxis.axisLabel.color,
labelOpacity: 1,
labelFillOpacity: 1,
labelFontSize: xAxis.axisLabel.fontSize,
tick: xAxis.axisLabel.show,
@@ -436,6 +444,7 @@ export class Area extends G2ChartView {
lineLineDash,
label: yAxis.axisLabel.show,
labelFill: yAxis.axisLabel.color,
labelOpacity: 1,
labelFillOpacity: 1,
labelFontSize: yAxis.axisLabel.fontSize,
tick: false,
@@ -501,7 +510,7 @@ export class Area extends G2ChartView {
}
}
defaultsDeep(options, tmpLegend)
return options
return configYAxisSeriesLegendDomain(chart, options)
}
protected configAssistLine(chart: Chart, options: G2Spec): G2Spec {
@@ -616,7 +625,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 +864,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 +887,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'
@@ -368,6 +374,7 @@ export class Line extends G2ChartView {
lineLineDash,
label: xAxis.axisLabel.show,
labelFill: xAxis.axisLabel.color,
labelOpacity: 1,
labelFillOpacity: 1,
labelFontSize: xAxis.axisLabel.fontSize,
grid: xAxis.splitLine.show,
@@ -420,6 +427,7 @@ export class Line extends G2ChartView {
lineLineDash,
label: yAxis.axisLabel.show,
labelFill: yAxis.axisLabel.color,
labelOpacity: 1,
labelFillOpacity: 1,
labelFontSize: yAxis.axisLabel.fontSize,
grid: yAxis.splitLine.show,
@@ -566,7 +574,7 @@ export class Line extends G2ChartView {
defaultsDeep(options, scaleOpt)
}
}
return options
return configYAxisSeriesLegendDomain(chart, options)
}
protected configAssistLine(chart: Chart, options: G2Spec): G2Spec {
@@ -683,7 +691,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
}