mirror of
https://github.com/dataease/dataease.git
synced 2026-06-16 20:42:07 +08:00
fix(图表): 线面图空值处理失效
This commit is contained in:
@@ -10,8 +10,8 @@ import { useEmitt } from '@/hooks/web/useEmitt'
|
||||
import { dvMainStoreWithOut } from '@/store/modules/data-visualization/dvMain'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import chartViewManager from '../../../js/panel'
|
||||
import { G2PlotChartView } from '../../../js/panel/types/impl/g2plot'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { type G2ChartView } from '../../../js/panel/types/impl/g2'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
@@ -54,7 +54,7 @@ const seriesColorState = reactive({
|
||||
seriesColorPickerId: 'body'
|
||||
})
|
||||
|
||||
const instance = ref<G2PlotChartView | undefined>()
|
||||
const instance = ref<G2ChartView | undefined>()
|
||||
|
||||
const colorsName = computed(() => {
|
||||
return props.sub ? 'subColors' : 'colors'
|
||||
@@ -85,7 +85,7 @@ const setupSeriesColor = () => {
|
||||
instance.value = chartViewManager.getChartView(
|
||||
props.chart.render,
|
||||
props.chart.type
|
||||
) as G2PlotChartView
|
||||
) as G2ChartView
|
||||
|
||||
if (!props.sub) {
|
||||
if (!needSetSeriesColor.value) {
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
import { parseJson } from '@/views/chart/components/js/util'
|
||||
import {
|
||||
handleBreakLineMultiDimension,
|
||||
handleIgnoreData,
|
||||
handleSetZeroMultiDimension,
|
||||
handleSetZeroSingleDimension,
|
||||
parseJson
|
||||
} from '@/views/chart/components/js/util'
|
||||
import { Chart as G2Chart, G2Spec } from '@antv/g2'
|
||||
|
||||
export type ViewSpec = { children?: G2Spec[]; [key: string]: any } & G2Spec
|
||||
@@ -9,70 +15,30 @@ export type Transform = {
|
||||
|
||||
export function handleEmptyDataStrategy<O extends ViewSpec>(chart: Chart, options: O): O {
|
||||
const { data } = options.children[0]
|
||||
const isChartMix = chart.type.includes('chart-mix')
|
||||
if (!data?.length) {
|
||||
return options
|
||||
}
|
||||
const strategy = parseJson(chart.senior).functionCfg.emptyDataStrategy
|
||||
if (strategy === 'ignoreData') {
|
||||
if (isChartMix) {
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
handleIgnoreData(data[i] as Record<string, any>[])
|
||||
}
|
||||
} else {
|
||||
handleIgnoreData(data)
|
||||
}
|
||||
handleIgnoreData(data)
|
||||
return options
|
||||
}
|
||||
const { yAxis, xAxisExt, extStack, extBubble } = chart
|
||||
const { yAxis, xAxisExt, extStack } = chart
|
||||
const multiDimension = yAxis?.length >= 2 || xAxisExt?.length > 0 || extStack?.length > 0
|
||||
switch (strategy) {
|
||||
case 'breakLine': {
|
||||
if (isChartMix) {
|
||||
if (data[0]) {
|
||||
if (xAxisExt?.length > 0 || extStack?.length > 0) {
|
||||
handleBreakLineMultiDimension(data[0] as Record<string, any>[])
|
||||
}
|
||||
}
|
||||
if (data[1]) {
|
||||
if (extBubble?.length > 0) {
|
||||
handleBreakLineMultiDimension(data[1] as Record<string, any>[])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (multiDimension) {
|
||||
handleBreakLineMultiDimension(data)
|
||||
}
|
||||
}
|
||||
return {
|
||||
...options,
|
||||
connectNulls: false
|
||||
if (multiDimension) {
|
||||
handleBreakLineMultiDimension(data)
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'setZero': {
|
||||
if (isChartMix) {
|
||||
if (data[0]) {
|
||||
if (xAxisExt?.length > 0 || extStack?.length > 0) {
|
||||
handleSetZeroMultiDimension(data[0] as Record<string, any>[])
|
||||
} else {
|
||||
handleSetZeroSingleDimension(data[0] as Record<string, any>[])
|
||||
}
|
||||
}
|
||||
if (data[1]) {
|
||||
if (extBubble?.length > 0) {
|
||||
handleSetZeroMultiDimension(data[1] as Record<string, any>[], true)
|
||||
} else {
|
||||
handleSetZeroSingleDimension(data[1] as Record<string, any>[], true)
|
||||
}
|
||||
}
|
||||
if (multiDimension) {
|
||||
// 多维度置0
|
||||
handleSetZeroMultiDimension(data)
|
||||
} else {
|
||||
if (multiDimension) {
|
||||
// 多维度置0
|
||||
handleSetZeroMultiDimension(data)
|
||||
} else {
|
||||
// 单维度置0
|
||||
handleSetZeroSingleDimension(data)
|
||||
}
|
||||
// 单维度置0
|
||||
handleSetZeroSingleDimension(data)
|
||||
}
|
||||
break
|
||||
}
|
||||
@@ -80,109 +46,6 @@ export function handleEmptyDataStrategy<O extends ViewSpec>(chart: Chart, option
|
||||
return options
|
||||
}
|
||||
|
||||
function handleBreakLineMultiDimension(data) {
|
||||
const dimensionInfoMap = new Map()
|
||||
const subDimensionSet = new Set()
|
||||
const quotaMap = new Map<string, { id: string }[]>()
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const item = data[i]
|
||||
const dimensionInfo = dimensionInfoMap.get(item.field)
|
||||
if (dimensionInfo) {
|
||||
dimensionInfo.set.add(item.category)
|
||||
} else {
|
||||
dimensionInfoMap.set(item.field, { set: new Set([item.category]), index: i })
|
||||
}
|
||||
subDimensionSet.add(item.category)
|
||||
quotaMap.set(item.category, item.quotaList)
|
||||
}
|
||||
// Map 是按照插入顺序排序的,所以插入索引往后推
|
||||
let insertCount = 0
|
||||
dimensionInfoMap.forEach((dimensionInfo, field) => {
|
||||
if (dimensionInfo.set.size < subDimensionSet.size) {
|
||||
let subInsertIndex = 0
|
||||
subDimensionSet.forEach(dimension => {
|
||||
if (!dimensionInfo.set.has(dimension)) {
|
||||
data.splice(dimensionInfo.index + insertCount + subInsertIndex, 0, {
|
||||
field,
|
||||
value: null,
|
||||
category: dimension,
|
||||
quotaList: quotaMap.get(dimension as string)
|
||||
})
|
||||
}
|
||||
subInsertIndex++
|
||||
})
|
||||
insertCount += subDimensionSet.size - dimensionInfo.set.size
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function handleSetZeroMultiDimension(data: Record<string, any>[], isExt = false) {
|
||||
const dimensionInfoMap = new Map()
|
||||
const subDimensionSet = new Set()
|
||||
const quotaMap = new Map<string, { id: string }[]>()
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const item = data[i]
|
||||
if (item.value === null) {
|
||||
item.value = 0
|
||||
if (isExt) {
|
||||
item.valueExt = 0
|
||||
}
|
||||
}
|
||||
const dimensionInfo = dimensionInfoMap.get(item.field)
|
||||
if (dimensionInfo) {
|
||||
dimensionInfo.set.add(item.category)
|
||||
} else {
|
||||
dimensionInfoMap.set(item.field, { set: new Set([item.category]), index: i })
|
||||
}
|
||||
subDimensionSet.add(item.category)
|
||||
quotaMap.set(item.category, item.quotaList)
|
||||
}
|
||||
let insertCount = 0
|
||||
dimensionInfoMap.forEach((dimensionInfo, field) => {
|
||||
if (dimensionInfo.set.size < subDimensionSet.size) {
|
||||
let subInsertIndex = 0
|
||||
subDimensionSet.forEach(dimension => {
|
||||
if (!dimensionInfo.set.has(dimension)) {
|
||||
const _temp = {
|
||||
field,
|
||||
value: 0,
|
||||
category: dimension,
|
||||
quotaList: quotaMap.get(dimension as string)
|
||||
} as any
|
||||
if (isExt) {
|
||||
_temp.valueExt = 0
|
||||
}
|
||||
|
||||
data.splice(dimensionInfo.index + insertCount + subInsertIndex, 0, _temp)
|
||||
}
|
||||
subInsertIndex++
|
||||
})
|
||||
insertCount += subDimensionSet.size - dimensionInfo.set.size
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function handleSetZeroSingleDimension(data: Record<string, any>[], isExt = false) {
|
||||
data.forEach(item => {
|
||||
if (item.value === null) {
|
||||
if (!isExt) {
|
||||
item.value = 0
|
||||
} else {
|
||||
item.valueExt = 0
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function handleIgnoreData(data: Record<string, any>[]) {
|
||||
for (let i = data.length - 1; i >= 0; i--) {
|
||||
const item = data[i]
|
||||
if (item.value === null) {
|
||||
data.splice(i, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function tooltipWrapperId(container: string) {
|
||||
return 'G2-TOOLTIP-WRAPPER-' + container
|
||||
}
|
||||
|
||||
@@ -3,6 +3,10 @@ import {
|
||||
flow,
|
||||
getLineConditions,
|
||||
getLineLabelColorByCondition,
|
||||
handleBreakLineMultiDimension,
|
||||
handleIgnoreData,
|
||||
handleSetZeroMultiDimension,
|
||||
handleSetZeroSingleDimension,
|
||||
hexColorToRGBA,
|
||||
parseJson,
|
||||
randomString,
|
||||
@@ -652,9 +656,43 @@ export class Area extends G2ChartView {
|
||||
return options
|
||||
}
|
||||
|
||||
protected configEmptyDataStrategy(chart: Chart, options: G2Spec): G2Spec {
|
||||
const { functionCfg } = parseJson(chart.senior)
|
||||
const { emptyDataStrategy } = functionCfg
|
||||
const [areaMark, lineMark] = options.children
|
||||
const data = options.data.value
|
||||
const multiDimension = chart.yAxis?.length > 1
|
||||
switch (emptyDataStrategy) {
|
||||
case 'breakLine': {
|
||||
if (multiDimension) {
|
||||
handleBreakLineMultiDimension(data)
|
||||
}
|
||||
merge(areaMark, { style: { connect: false } })
|
||||
merge(lineMark, { style: { connect: false } })
|
||||
break
|
||||
}
|
||||
case 'ignoreData': {
|
||||
handleIgnoreData(data)
|
||||
break
|
||||
}
|
||||
case 'setZero': {
|
||||
if (multiDimension) {
|
||||
// 多维度置0
|
||||
handleSetZeroMultiDimension(data)
|
||||
} else {
|
||||
// 单维度置0
|
||||
handleSetZeroSingleDimension(data)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
protected setupOptions(chart: Chart, options: G2Spec, context: Record<string, any>): G2Spec {
|
||||
return flow(
|
||||
this.configTheme,
|
||||
this.configEmptyDataStrategy,
|
||||
this.configColor,
|
||||
this.configLabel,
|
||||
this.configBasicStyle,
|
||||
@@ -866,11 +904,44 @@ export class StackArea extends Area {
|
||||
return setUpStackSeriesColor(chart, data)
|
||||
}
|
||||
|
||||
protected configEmptyDataStrategy(chart: Chart, options: G2Spec): G2Spec {
|
||||
const { functionCfg } = parseJson(chart.senior)
|
||||
const { emptyDataStrategy } = functionCfg
|
||||
const [areaMark, lineMark] = options.children
|
||||
const data = options.data.value
|
||||
const multiDimension = chart.yAxis?.length > 1 || chart.extStack?.length > 0
|
||||
switch (emptyDataStrategy) {
|
||||
case 'breakLine': {
|
||||
if (multiDimension) {
|
||||
handleBreakLineMultiDimension(data)
|
||||
}
|
||||
merge(areaMark, { style: { connect: false } })
|
||||
merge(lineMark, { style: { connect: false } })
|
||||
break
|
||||
}
|
||||
case 'ignoreData': {
|
||||
handleIgnoreData(data)
|
||||
break
|
||||
}
|
||||
case 'setZero': {
|
||||
if (multiDimension) {
|
||||
// 多维度置0
|
||||
handleSetZeroMultiDimension(data)
|
||||
} else {
|
||||
// 单维度置0
|
||||
handleSetZeroSingleDimension(data)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super('area-stack')
|
||||
this.baseOptions = {
|
||||
...this.baseOptions,
|
||||
transform: [{ type: 'stackY' }]
|
||||
transform: [{ type: 'stackY', orderBy: 'series' }]
|
||||
}
|
||||
delete this.propertyInner.threshold
|
||||
this.properties = this.properties.filter(item => item !== 'threshold')
|
||||
|
||||
@@ -3,6 +3,10 @@ import {
|
||||
flow,
|
||||
getLineConditions,
|
||||
getLineLabelColorByCondition,
|
||||
handleBreakLineMultiDimension,
|
||||
handleIgnoreData,
|
||||
handleSetZeroMultiDimension,
|
||||
handleSetZeroSingleDimension,
|
||||
hexColorToRGBA,
|
||||
parseJson,
|
||||
randomString,
|
||||
@@ -726,9 +730,42 @@ export class Line extends G2ChartView {
|
||||
return options
|
||||
}
|
||||
|
||||
protected configEmptyDataStrategy(chart: Chart, options: G2Spec): G2Spec {
|
||||
const { functionCfg } = parseJson(chart.senior)
|
||||
const { emptyDataStrategy } = functionCfg
|
||||
const [lineMark] = options.children
|
||||
const data = options.data.value
|
||||
const multiDimension = chart.yAxis?.length > 1 || chart.xAxisExt?.length > 0
|
||||
switch (emptyDataStrategy) {
|
||||
case 'breakLine': {
|
||||
if (multiDimension) {
|
||||
handleBreakLineMultiDimension(data)
|
||||
}
|
||||
merge(lineMark, { style: { connect: false } })
|
||||
break
|
||||
}
|
||||
case 'ignoreData': {
|
||||
handleIgnoreData(data)
|
||||
break
|
||||
}
|
||||
case 'setZero': {
|
||||
if (multiDimension) {
|
||||
// 多维度置0
|
||||
handleSetZeroMultiDimension(data)
|
||||
} else {
|
||||
// 单维度置0
|
||||
handleSetZeroSingleDimension(data)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
protected setupOptions(chart: Chart, options: G2Spec): G2Spec {
|
||||
return flow(
|
||||
this.configTheme,
|
||||
this.configEmptyDataStrategy,
|
||||
this.configColor,
|
||||
this.configLabel,
|
||||
this.configBasicStyle,
|
||||
|
||||
@@ -267,80 +267,7 @@ export const notSupportAccumulateViews = [
|
||||
'stock-line'
|
||||
]
|
||||
|
||||
export function handleEmptyDataStrategy<O extends PickOptions>(chart: Chart, options: O): O {
|
||||
const { data } = options as unknown as Options
|
||||
const isChartMix = chart.type.includes('chart-mix')
|
||||
if (!data?.length) {
|
||||
return options
|
||||
}
|
||||
const strategy = parseJson(chart.senior).functionCfg.emptyDataStrategy
|
||||
if (strategy === 'ignoreData') {
|
||||
if (isChartMix) {
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
handleIgnoreData(data[i] as Record<string, any>[])
|
||||
}
|
||||
} else {
|
||||
handleIgnoreData(data)
|
||||
}
|
||||
return options
|
||||
}
|
||||
const { yAxis, xAxisExt, extStack, extBubble } = chart
|
||||
const multiDimension = yAxis?.length >= 2 || xAxisExt?.length > 0 || extStack?.length > 0
|
||||
switch (strategy) {
|
||||
case 'breakLine': {
|
||||
if (isChartMix) {
|
||||
if (data[0]) {
|
||||
if (xAxisExt?.length > 0 || extStack?.length > 0) {
|
||||
handleBreakLineMultiDimension(data[0] as Record<string, any>[])
|
||||
}
|
||||
}
|
||||
if (data[1]) {
|
||||
if (extBubble?.length > 0) {
|
||||
handleBreakLineMultiDimension(data[1] as Record<string, any>[])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (multiDimension) {
|
||||
handleBreakLineMultiDimension(data)
|
||||
}
|
||||
}
|
||||
return {
|
||||
...options,
|
||||
connectNulls: false
|
||||
}
|
||||
}
|
||||
case 'setZero': {
|
||||
if (isChartMix) {
|
||||
if (data[0]) {
|
||||
if (xAxisExt?.length > 0 || extStack?.length > 0) {
|
||||
handleSetZeroMultiDimension(data[0] as Record<string, any>[])
|
||||
} else {
|
||||
handleSetZeroSingleDimension(data[0] as Record<string, any>[])
|
||||
}
|
||||
}
|
||||
if (data[1]) {
|
||||
if (extBubble?.length > 0) {
|
||||
handleSetZeroMultiDimension(data[1] as Record<string, any>[], true)
|
||||
} else {
|
||||
handleSetZeroSingleDimension(data[1] as Record<string, any>[], true)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (multiDimension) {
|
||||
// 多维度置0
|
||||
handleSetZeroMultiDimension(data)
|
||||
} else {
|
||||
// 单维度置0
|
||||
handleSetZeroSingleDimension(data)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
function handleBreakLineMultiDimension(data) {
|
||||
export function handleBreakLineMultiDimension(data) {
|
||||
const dimensionInfoMap = new Map()
|
||||
const subDimensionSet = new Set()
|
||||
const quotaMap = new Map<string, { id: string }[]>()
|
||||
@@ -376,17 +303,14 @@ function handleBreakLineMultiDimension(data) {
|
||||
})
|
||||
}
|
||||
|
||||
function handleSetZeroMultiDimension(data: Record<string, any>[], isExt = false) {
|
||||
export function handleSetZeroMultiDimension(data: Record<string, any>[], valueProp = 'value') {
|
||||
const dimensionInfoMap = new Map()
|
||||
const subDimensionSet = new Set()
|
||||
const quotaMap = new Map<string, { id: string }[]>()
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const item = data[i]
|
||||
if (item.value === null) {
|
||||
item.value = 0
|
||||
if (isExt) {
|
||||
item.valueExt = 0
|
||||
}
|
||||
if (item[valueProp] === null) {
|
||||
item[valueProp] = 0
|
||||
}
|
||||
const dimensionInfo = dimensionInfoMap.get(item.field)
|
||||
if (dimensionInfo) {
|
||||
@@ -405,13 +329,10 @@ function handleSetZeroMultiDimension(data: Record<string, any>[], isExt = false)
|
||||
if (!dimensionInfo.set.has(dimension)) {
|
||||
const _temp = {
|
||||
field,
|
||||
value: 0,
|
||||
[valueProp]: 0,
|
||||
category: dimension,
|
||||
quotaList: quotaMap.get(dimension as string)
|
||||
} as any
|
||||
if (isExt) {
|
||||
_temp.valueExt = 0
|
||||
}
|
||||
|
||||
data.splice(dimensionInfo.index + insertCount + subInsertIndex, 0, _temp)
|
||||
}
|
||||
@@ -422,19 +343,15 @@ function handleSetZeroMultiDimension(data: Record<string, any>[], isExt = false)
|
||||
})
|
||||
}
|
||||
|
||||
function handleSetZeroSingleDimension(data: Record<string, any>[], isExt = false) {
|
||||
export function handleSetZeroSingleDimension(data: Record<string, any>[], valueProp = 'value') {
|
||||
data.forEach(item => {
|
||||
if (item.value === null) {
|
||||
if (!isExt) {
|
||||
item.value = 0
|
||||
} else {
|
||||
item.valueExt = 0
|
||||
}
|
||||
if (item[valueProp] === null) {
|
||||
item[valueProp] = 0
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function handleIgnoreData(data: Record<string, any>[]) {
|
||||
export function handleIgnoreData(data: Record<string, any>[]) {
|
||||
for (let i = data.length - 1; i >= 0; i--) {
|
||||
const item = data[i]
|
||||
if (item.value === null) {
|
||||
|
||||
Reference in New Issue
Block a user