fix(图表): 优化子弹图提示以及图例的显示逻辑

This commit is contained in:
jianneng-fit2cloud
2026-04-21 11:37:53 +08:00
parent f228d099f6
commit 1f67ea09bb
2 changed files with 109 additions and 50 deletions

View File

@@ -1,5 +1,5 @@
<script lang="tsx" setup>
import { reactive, onMounted, watch } from 'vue'
import { reactive, onMounted, watch, nextTick, ref } from 'vue'
import { COLOR_PANEL, DEFAULT_MISC } from '@/views/chart/components/editor/util/chart'
import { cloneDeep, defaultsDeep } from 'lodash-es'
import { useI18n } from '@/hooks/web/useI18n'
@@ -42,20 +42,32 @@ const state = reactive({
})
const emit = defineEmits(['onBasicStyleChange', 'onMiscChange'])
const syncingMisc = ref(false)
watch(
() => props.chart.customAttr.misc,
() => {
if (syncingMisc.value) {
return
}
init()
},
{ deep: true }
)
const emitMiscChange = (payload, prop?) => {
syncingMisc.value = true
emit('onMiscChange', payload, prop)
nextTick(() => {
syncingMisc.value = false
})
}
const changeStyle = (prop?) => {
if (state.bulletRangeForm.bar.ranges.showType === 'fixed' && state.rangeList.length) {
state.bulletRangeForm.bar.ranges.fixedRange = cloneDeep(state.rangeList)
}
emit('onMiscChange', { data: { bullet: { ...state.bulletRangeForm } }, requestData: true }, prop)
emitMiscChange({ data: { bullet: { ...state.bulletRangeForm } }, requestData: true }, prop)
}
const changeRangeNumber = () => {
if (state.bulletRangeForm.bar.ranges.fixedRangeNumber === null) {
@@ -170,7 +182,7 @@ onMounted(() => {
<el-radio-group
:effect="themes"
v-model="state.bulletRangeForm.bar.ranges.showType"
@change="changeShowType()"
@change="changeShowType"
>
<el-radio :effect="themes" label="dynamic">{{ t('chart.dynamic') }}</el-radio>
<el-radio :effect="themes" label="fixed">{{ t('chart.fix') }}</el-radio>

View File

@@ -25,6 +25,11 @@ import { isEmpty } from 'lodash-es'
const { t } = useI18n()
const BULLET_MEASURE_KEY = '__de_bullet_measure__'
const BULLET_TARGET_KEY = '__de_bullet_target__'
const BULLET_DYNAMIC_RANGE_KEY = '__de_bullet_range_dynamic__'
const getFixedRangeKey = (index: number) => `__de_bullet_range_${index}__`
/**
* 子弹图
*/
@@ -174,7 +179,8 @@ export class BulletGraph extends G2ChartView<RuntimeOptions, G2Bullet> {
const { bullet } = parseJson(chart.customAttr).misc
const isDynamic = bullet.bar.ranges.showType === 'dynamic'
const showRangeLegend = customStyleLegend?.showRange
const rangeLegendNames = []
const rangeLegendKeys: string[] = []
const rangeLegendLabelMap: Record<string, string> = {}
// 背景颜色,固定区间背景时,按大小降序
const rangeColor = isDynamic
? chart.extBubble?.length
@@ -188,8 +194,10 @@ export class BulletGraph extends G2ChartView<RuntimeOptions, G2Bullet> {
const ranges = bullet.bar.ranges.fixedRange || []
ranges.sort((a, b) => (a.fixedRangeValue ?? 0) - (b.fixedRangeValue ?? 0))
if (showRangeLegend && !isDynamic) {
ranges.forEach(item => {
rangeLegendNames.push(item.name)
ranges.forEach((item, index) => {
const key = getFixedRangeKey(index)
rangeLegendKeys.push(key)
rangeLegendLabelMap[key] = item.name ?? ''
})
}
ranges.forEach((item, index) => {
@@ -200,7 +208,7 @@ export class BulletGraph extends G2ChartView<RuntimeOptions, G2Bullet> {
encode: {
x: 'title',
y: [prev ? prev.fixedRangeValue : 0, item.fixedRangeValue],
...(showRangeLegend ? { color: () => item.name } : {})
...(showRangeLegend ? { color: () => getFixedRangeKey(index) } : {})
},
interaction: {
legendFilter: false
@@ -218,14 +226,15 @@ export class BulletGraph extends G2ChartView<RuntimeOptions, G2Bullet> {
if (chart.extBubble?.length) {
const rangeName = chart.extBubble[0]?.chartShowName || chart.extBubble[0]?.name
if (showRangeLegend) {
rangeLegendNames.push(rangeName)
rangeLegendKeys.push(BULLET_DYNAMIC_RANGE_KEY)
rangeLegendLabelMap[BULLET_DYNAMIC_RANGE_KEY] = rangeName
}
childrens.push({
type: 'interval',
encode: {
x: 'title',
y: 'ranges',
...(showRangeLegend ? { color: () => rangeName } : {})
...(showRangeLegend ? { color: () => BULLET_DYNAMIC_RANGE_KEY } : {})
},
interaction: {
legendFilter: false
@@ -239,14 +248,12 @@ export class BulletGraph extends G2ChartView<RuntimeOptions, G2Bullet> {
}
}
// 实际值与目标值
const measureName =
chart.yAxis[0]?.chartShowName || bullet.bar.measures.name || chart.yAxis[0]?.name
const measures = {
type: 'interval',
encode: {
x: 'title',
y: 'measures',
color: () => measureName,
color: () => BULLET_MEASURE_KEY,
shape: 'rect'
},
interaction: {
@@ -262,17 +269,12 @@ export class BulletGraph extends G2ChartView<RuntimeOptions, G2Bullet> {
}
: false
}
let targetName =
chart.yAxisExt[0]?.chartShowName || bullet.bar.target.name || chart.yAxisExt[0]?.name
if (targetName === measureName) {
targetName = `${targetName} `
}
const target = {
type: 'point',
encode: {
x: 'title',
y: 'target',
color: () => targetName,
color: () => BULLET_TARGET_KEY,
shape: basicStyle.layout === 'horizontal' ? 'line' : 'hyphen',
size: bullet.bar.target.size
},
@@ -292,7 +294,11 @@ export class BulletGraph extends G2ChartView<RuntimeOptions, G2Bullet> {
...options,
scale: {
color: {
domain: [...rangeLegendNames, targetName, measureName],
domain: [
...(showRangeLegend ? rangeLegendKeys : []),
BULLET_TARGET_KEY,
BULLET_MEASURE_KEY
],
range: [
...(showRangeLegend ? [].concat(rangeColor) : []),
...[].concat(bullet.bar.target.fill),
@@ -383,16 +389,47 @@ export class BulletGraph extends G2ChartView<RuntimeOptions, G2Bullet> {
const { ranges } = bullet.bar
const targetName =
chart.yAxisExt[0]?.chartShowName || bullet.bar.target.name || chart.yAxisExt[0]?.name
const measureName =
chart.yAxis[0]?.chartShowName || bullet.bar.measures.name || chart.yAxis[0]?.name
const rangeLegendLabelMap: Record<string, string> = {}
const showRangeLegend = parseJson(chart.customStyle).legend?.showRange
const getLegendKey = d => (typeof d === 'string' ? d : d?.id ?? d?.name ?? '')
if (showRangeLegend) {
if (bullet.bar.ranges.showType === 'dynamic') {
const rangeName = chart.extBubble?.[0]?.chartShowName || chart.extBubble?.[0]?.name
if (rangeName) {
rangeLegendLabelMap[BULLET_DYNAMIC_RANGE_KEY] = rangeName
}
} else {
;(ranges.fixedRange || [])
.sort((a, b) => (a.fixedRangeValue ?? 0) - (b.fixedRangeValue ?? 0))
.forEach((item, index) => {
rangeLegendLabelMap[getFixedRangeKey(index)] = item.name
})
}
}
const baseLegend = tmpOptions.legend ? (tmpOptions.legend as any) : {}
const tmpLegend = {
color: {
...baseLegend,
itemMarkerSize: ranges.symbolSize,
itemMarker: d => {
if (d === targetName) {
const key = getLegendKey(d)
if (key === BULLET_TARGET_KEY) {
return 'line'
}
return ranges.symbol
},
itemLabelText: d => {
const key = getLegendKey(d)
return (
rangeLegendLabelMap[key] ||
(key === BULLET_TARGET_KEY
? targetName
: key === BULLET_MEASURE_KEY
? measureName
: String(key))
)
}
}
}
@@ -448,7 +485,9 @@ export class BulletGraph extends G2ChartView<RuntimeOptions, G2Bullet> {
private buildTooltipFormatterMap(tooltipAttr: any): Record<string, any> {
const formatterMap: Record<string, any> = {}
tooltipAttr.seriesTooltipFormatter
?.filter(i => i.show)
?.filter(
i => i.show && ['-yAxis', '-yAxisExt', 'extBubble'].some(k => i.seriesId.includes(k))
)
.forEach(next => {
switch (next.axisType) {
case 'yAxis':
@@ -522,6 +561,7 @@ export class BulletGraph extends G2ChartView<RuntimeOptions, G2Bullet> {
const isDynamic = bullet.bar.ranges.showType === 'dynamic'
const rangeFormatter = chart.extBubble?.[0]
const chartData = options.data?.find(item => item.title === titleValue)
const showRangeLegend = parseJson(chart.customStyle).legend?.showRange
const result = []
const axisFormatterMap = {
@@ -532,9 +572,6 @@ export class BulletGraph extends G2ChartView<RuntimeOptions, G2Bullet> {
const visibleKeys = hasSeriesFormatter ? Object.keys(formatterMap) : ['measures', 'target']
visibleKeys.forEach(field => {
if (field === '记录数*') {
return
}
const formatter = formatterMap?.[field] ?? axisFormatterMap[field]
if (!formatter) {
return
@@ -548,6 +585,9 @@ export class BulletGraph extends G2ChartView<RuntimeOptions, G2Bullet> {
let color = bullet.bar[field]?.fill ?? 'grey'
if (field === 'ranges') {
if (!showRangeLegend) {
return
}
if (!isDynamic && rangeFormatter) {
name = isEmpty(rangeFormatter.chartShowName)
? rangeFormatter.name
@@ -569,33 +609,40 @@ export class BulletGraph extends G2ChartView<RuntimeOptions, G2Bullet> {
return result
}
if (!showRangeLegend) {
return result
}
const ranges = chartData?.ranges ?? []
const rangeFormatterCfg = formatterMap.ranges?.formatterCfg ?? rangeFormatter?.formatterCfg
ranges.forEach((range, index) => {
const value = isDynamic
? this.formatTooltipValue(
chartData?.tooltipMinRanges?.[0] ?? chartData?.minRanges?.[0],
rangeFormatterCfg
)
: this.formatTooltipValue(range, rangeFormatterCfg)
let name = ''
let color: string | string[] = 'grey'
if (isDynamic && rangeFormatter) {
name = isEmpty(rangeFormatter.chartShowName)
? rangeFormatter.name
: rangeFormatter.chartShowName
color = bullet.bar.ranges.fill
} else {
const customRange = bullet.bar.ranges.fixedRange?.[index]
name = customRange?.name
? customRange.name
: isEmpty(rangeFormatter?.chartShowName)
? rangeFormatter?.name
: rangeFormatter?.chartShowName
color = customRange?.fill ?? 'grey'
}
result.push({ color, name, value })
})
const rangeFormatterCfg = formatterMap['ranges']?.formatterCfg ?? rangeFormatter?.formatterCfg
const shouldShowRanges = isDynamic ? Boolean(formatterMap['ranges']) : showRangeLegend
if (shouldShowRanges) {
ranges.forEach((range, index) => {
const value = isDynamic
? this.formatTooltipValue(
chartData?.tooltipMinRanges?.[0] ?? chartData?.minRanges?.[0],
rangeFormatterCfg
)
: this.formatTooltipValue(range, rangeFormatterCfg)
let name = ''
let color: string | string[] = 'grey'
if (isDynamic && rangeFormatter) {
name = isEmpty(rangeFormatter.chartShowName)
? rangeFormatter.name
: rangeFormatter.chartShowName
color = bullet.bar.ranges.fill
} else {
const customRange = bullet.bar.ranges.fixedRange?.[index]
name = customRange?.name
? customRange.name
: isEmpty(rangeFormatter?.chartShowName)
? rangeFormatter?.name
: rangeFormatter?.chartShowName
color = customRange?.fill ?? 'grey'
}
result.push({ color, name, value })
})
}
const dynamicTooltipValue =
chart.data?.data?.find(d => d.field === titleValue)?.dynamicTooltipValue || []