mirror of
https://github.com/dataease/dataease.git
synced 2026-06-16 20:42:07 +08:00
Merge remote-tracking branch 'origin/dev-v3' into dev-v3
This commit is contained in:
@@ -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<ViewSpec, G2Column> {
|
||||
},
|
||||
...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<ViewSpec, G2Column> {
|
||||
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<ViewSpec, G2Column> {
|
||||
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
|
||||
@@ -516,10 +526,10 @@ export class Bar extends G2ChartView<ViewSpec, G2Column> {
|
||||
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) {
|
||||
@@ -530,6 +540,8 @@ export class Bar extends G2ChartView<ViewSpec, G2Column> {
|
||||
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))
|
||||
@@ -570,7 +582,11 @@ export class Bar extends G2ChartView<ViewSpec, G2Column> {
|
||||
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',
|
||||
@@ -832,9 +848,15 @@ export class Bar extends G2ChartView<ViewSpec, G2Column> {
|
||||
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,
|
||||
|
||||
@@ -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<G2Column>): Promise<G2Column> {
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -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<any, number>()
|
||||
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<any, any>()
|
||||
const indexByField = new Map<any, number>()
|
||||
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
|
||||
}
|
||||
@@ -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<G2Column>): Promise<G2Column> {
|
||||
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 = {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 })
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user