feat(图表): 支持堆叠条形图

This commit is contained in:
jianneng-fit2cloud
2025-05-21 11:10:14 +08:00
committed by jianneng-fit2cloud
parent 9bd098d216
commit 6b1dd573bf
2 changed files with 174 additions and 2 deletions

View File

@@ -3,11 +3,11 @@ 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 { flow, hexColorToRGBA, parseJson } from '@/views/chart/components/js/util'
import { ViewSpec } from '@/views/chart/components/js/panel/charts/g2/bar/barUtil'
import { useI18n } from '@/hooks/web/useI18n'
import { Bar } from '@/views/chart/components/js/panel/charts/g2/bar/bar'
import { getLineDash } from '@/views/chart/components/js/panel/common/common_antv'
import { getLineDash, setGradientColor } from '@/views/chart/components/js/panel/common/common_antv'
import { valueFormatter } from '@/views/chart/components/js/formatter'
import { Chart } from '@antv/g2'
@@ -52,6 +52,28 @@ export class HorizontalBar extends Bar {
}
axis: AxisType[] = [...BAR_AXIS_TYPE]
protected configBasicStyle(chart: Chart, options: ViewSpec): ViewSpec {
const { children } = options
const { basicStyle } = parseJson(chart.customAttr) || {}
const colors =
basicStyle?.colors?.map(ele =>
basicStyle.gradient
? setGradientColor(hexColorToRGBA(ele, basicStyle.alpha), true)
: hexColorToRGBA(ele, basicStyle.alpha)
) || []
const scale = { color: { range: colors }, y: { nice: true } }
const style =
basicStyle?.radiusColumnBar === 'topRoundAngle'
? {
radiusTopLeft: basicStyle.columnBarRightAngleRadius,
radiusTopRight: basicStyle.columnBarRightAngleRadius
}
: basicStyle?.radiusColumnBar === 'roundAngle'
? { radius: basicStyle.columnBarRightAngleRadius }
: { radius: 0 }
return { ...options, children: [{ ...children[0], scale, style }, ...children.slice(1)] }
}
protected configLabel(chart: Chart, options: ViewSpec): ViewSpec {
const tmpOptions = super.configLabel(chart, options)
const { children } = tmpOptions

View File

@@ -0,0 +1,150 @@
import { BAR_EDITOR_PROPERTY } from '@/views/chart/components/js/panel/charts/g2/bar/common'
import { flow, parseJson } from '@/views/chart/components/js/util'
import {
createTooltipWrapper,
tooltipCss,
ViewSpec
} from '@/views/chart/components/js/panel/charts/g2/bar/barUtil'
import { useI18n } from '@/hooks/web/useI18n'
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 { Chart } from '@antv/g2'
import { HorizontalBar } from '@/views/chart/components/js/panel/charts/g2/bar/horizontal-bar'
import { isEmpty } from 'lodash-es'
const { t } = useI18n()
/**
* 堆叠条形图
*/
export class HorizontalStackBar extends HorizontalBar {
properties = BAR_EDITOR_PROPERTY.filter(ele => ele !== 'threshold')
axisConfig = {
...this['axisConfig'],
extStack: {
name: `${t('chart.stack_item')} / ${t('chart.dimension')}`,
type: 'd',
limit: 1,
allowEmpty: true
}
}
propertyInner = {
...this['propertyInner'],
'label-selector': ['color', 'fontSize', 'hPosition', 'labelFormatter'],
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'tooltipFormatter', 'show']
}
protected configLabel(chart: Chart, options: ViewSpec): ViewSpec {
const { label: labelAttr } = parseJson(chart.customAttr) || {}
if (!labelAttr?.show) return options
const { children } = options
const position = {
position: labelAttr.position === 'middle' ? 'inside' : labelAttr.position,
textAlign: 'start',
dy: labelAttr.position === 'top' ? -10 : 0,
dx: 0
}
const transform = [
{ type: 'exceedAdjust' },
...(labelAttr.fullDisplay ? [] : [{ type: 'overlapHide' }])
]
const labels = [
{
text: 'value',
fillOpacity: 1,
fill: labelAttr.color,
fontSize: labelAttr.fontSize,
...position,
formatter: (value, _data) => valueFormatter(value, labelAttr.labelFormatter),
transform
}
]
return {
...options,
children: [{ ...children[0], labels }, ...children.slice(1)]
}
}
protected configTooltip(chart: Chart, options: ViewSpec): ViewSpec {
const { children } = options
const { tooltip } = parseJson(chart.customAttr)
if (!tooltip.show) {
return {
...options,
children: [{ ...children[0], tooltip: false }, ...children.slice(1)]
}
}
const tooltipOptions: ViewSpec = {
tooltip: a => a,
interaction: {
tooltip: {
mount: createTooltipWrapper(chart),
css: tooltipCss(tooltip),
enterable: true,
shared: true,
bounding: {
x: 0,
y: 0
},
position: 'top-right',
render: (_, { title, items: originalItems }) => {
const titleHtml = TOOLTIP_TITLE_TPL.replace('{title}', title)
const tooltipItems = originalItems
const result = []
tooltipItems.forEach(item => {
const value = valueFormatter(item.value, tooltip.tooltipFormatter)
const name = isEmpty(item.category) ? item.field : item.category
result.push({ ...item, name, value })
})
const itemsHtml = result
.map(item => {
const marker = item.color
const label = item.name
const value = item.value
return TOOLTIP_ITEM_TPL.replace('{marker}', marker)
.replace('{label}', label)
.replace('{value}', value)
})
.join('')
const listHtml = `<ul class="g2-tooltip-list" style="margin: 0px; list-style-type: none; padding: 0px;">${itemsHtml}</ul>`
return `${titleHtml}${listHtml}`
}
}
}
}
return {
...options,
children: [{ ...children[0], ...tooltipOptions }, ...children.slice(1)]
}
}
protected setupOptions(chart: Chart, options: ViewSpec): ViewSpec {
return flow(
this.configTheme,
this.configBasicStyle,
this.configLabel,
this.configTooltip,
this.configLegend,
this.configXAxis,
this.configYAxis,
this.configAnalyse,
this.configBarConditions
)(chart, options, {}, this)
}
constructor(name = 'bar-stack-horizontal') {
super(name)
Object.assign(this.intervalOptions, {
transform: [{ type: 'stackY' }],
coordinate: { transform: [{ type: 'transpose' }] }
})
this.axis = [...this.axis, 'extStack']
}
}