fix(图表-象限图): 修复计算字段作为横纵轴时,无法正常显示的问题及配置样式优化

This commit is contained in:
jianneng-fit2cloud 2024-05-23 22:06:49 +08:00
parent 5cf485e1e8
commit 6e33ef9e8c
5 changed files with 99 additions and 103 deletions

View File

@ -557,17 +557,11 @@ public class ChartDataManage {
} else if (StringUtils.containsIgnoreCase(view.getType(), "quadrant")) {
Dimension2SQLObj.dimension2sqlObj(sqlMeta, xAxis, transFields(allFields), crossDs, dsMap);
yAxis.addAll(extBubble);
if(ObjectUtils.isNotEmpty(view.getExtTooltip())){
yAxis.addAll(new ArrayList<>(view.getExtTooltip()));
}
Quota2SQLObj.quota2sqlObj(sqlMeta, yAxis, transFields(allFields), crossDs, dsMap);
querySql = SQLProvider.createQuerySQL(sqlMeta, true, needOrder, view);
if (containDetailField(view) && ObjectUtils.isNotEmpty(viewFields)) {
detailFieldList.addAll(xAxis);
detailFieldList.addAll(viewFields);
Dimension2SQLObj.dimension2sqlObj(sqlMeta, detailFieldList, transFields(allFields), crossDs, dsMap);
String originSql = SQLProvider.createQuerySQL(sqlMeta, false, needOrder, view);
String limit = ((pageInfo.getGoPage() != null && pageInfo.getPageSize() != null) ? " LIMIT " + pageInfo.getPageSize() + " OFFSET " + (pageInfo.getGoPage() - 1) * pageInfo.getPageSize() : "");
detailFieldSql = originSql + limit;
}
} else if (StringUtils.equalsIgnoreCase("bar-range", view.getType())) {
sqlMeta.setChartType(view.getType());
Dimension2SQLObj.dimension2sqlObj(sqlMeta, xAxis, transFields(allFields), crossDs, dsMap);
@ -791,7 +785,7 @@ public class ChartDataManage {
} else if (StringUtils.containsIgnoreCase(view.getType(), "label")) {
mapChart = ChartDataBuild.transLabelChartData(xAxis, yAxis, view, data, isDrill);
} else if (StringUtils.containsIgnoreCase(view.getType(), "quadrant")) {
mapChart = ChartDataBuild.transQuadrantDataAntV(xAxis, yAxis, view, data, extBubble, isDrill);
mapChart = ChartDataBuild.transMixChartDataAntV(xAxis, yAxis, view, data, isDrill);
} else if (StringUtils.equalsIgnoreCase(view.getType(), "bar-range")) {
mapChart = ChartDataBuild.transBarRangeDataAntV(skipBarRange, barRangeDate, xAxisBase, xAxis, yAxis, view, data, isDrill);
} else {

View File

@ -137,11 +137,13 @@ onMounted(() => {
label-position="top"
>
<template v-if="showProperty('lineStyle')">
<label class="custom-form-item-label" :class="'custom-form-item-label--' + themes"
>{{ t('chart.quadrant') }}{{ t('chart.split_line') }}</label
>
<div style="display: flex">
<el-form-item class="form-item" :class="'form-item-' + themes" style="padding-right: 4px">
<el-form-item
:label="t('chart.split_line')"
class="form-item"
:class="'form-item-' + themes"
style="padding-right: 4px"
>
<el-color-picker
v-model="state.quadrantForm.lineStyle.stroke"
class="color-picker-style"
@ -152,6 +154,7 @@ onMounted(() => {
/>
</el-form-item>
<el-form-item class="form-item" :class="'form-item-' + themes" style="padding-left: 4px">
<template #label>&nbsp;</template>
<el-tooltip :content="t('chart.not_alpha')" :effect="toolTip" placement="top">
<el-select
style="width: 53px"
@ -170,6 +173,7 @@ onMounted(() => {
</el-tooltip>
</el-form-item>
<el-form-item class="form-item" :class="'form-item-' + themes" style="padding-left: 4px">
<template #label>&nbsp;</template>
<el-tooltip :content="t('chart.funnel_width')" :effect="toolTip" placement="top">
<el-input-number
style="width: 108px"
@ -229,18 +233,14 @@ onMounted(() => {
:label="t('chart.quadrant') + (index + 1)"
class="padding-tab"
>
<div style="flex-direction: row; justify-content: space-between">
<div style="margin-top: 8px">
<template v-if="showProperty('regionStyle')">
<div style="display: flex">
<label class="custom-form-item-label" :class="'custom-form-item-label--' + themes">{{
t('chart.backgroundColor')
}}</label>
</div>
<div style="display: flex">
<el-form-item
class="form-item"
:class="'form-item-' + themes"
style="padding-right: 4px"
:label="t('chart.backgroundColor')"
>
<el-color-picker
v-model="state.quadrantForm.regionStyle[index].fill"
@ -256,6 +256,7 @@ onMounted(() => {
:class="'form-item-' + themes"
style="padding-left: 4px"
>
<template #label>&nbsp;</template>
<el-tooltip :content="t('chart.not_alpha')" :effect="toolTip" placement="top">
<el-select
style="width: 53px"
@ -285,14 +286,12 @@ onMounted(() => {
@blur="changeStyle()"
/>
</el-form-item>
<label class="custom-form-item-label" :class="'custom-form-item-label--' + themes">
{{ t('chart.text') }}{{ t('chart.chart_style') }}</label
>
<div style="display: flex">
<el-form-item
class="form-item"
:class="'form-item-' + themes"
style="padding-right: 4px"
:label="t('chart.chart_style')"
>
<el-color-picker
v-model="l.style.fill"
@ -308,6 +307,7 @@ onMounted(() => {
:class="'form-item-' + themes"
style="padding-left: 4px"
>
<template #label>&nbsp;</template>
<el-tooltip :content="t('chart.not_alpha')" :effect="toolTip" placement="top">
<el-select
style="width: 53px"
@ -330,6 +330,7 @@ onMounted(() => {
:class="'form-item-' + themes"
style="padding-left: 4px"
>
<template #label>&nbsp;</template>
<el-tooltip :content="t('chart.font_size')" :effect="toolTip" placement="top">
<el-select
style="width: 108px"

View File

@ -153,15 +153,12 @@ onMounted(() => {
/>
</el-form-item>
<label class="custom-form-item-label" :class="'custom-form-item-label--' + themes"
>{{ t('chart.name') }}{{ t('chart.text') }}</label
>
<div style="display: flex">
<el-form-item
class="form-item"
:class="'form-item-' + themes"
v-if="showProperty('color')"
style="padding-right: 4px"
:label="t('chart.chart_style')"
>
<el-color-picker
v-model="state.axisForm.color"
@ -178,6 +175,7 @@ onMounted(() => {
v-if="showProperty('fontSize')"
style="padding-left: 4px"
>
<template #label>&nbsp;</template>
<el-tooltip content="字号" :effect="toolTip" placement="top">
<el-select
style="width: 108px"

View File

@ -129,15 +129,13 @@ onMounted(() => {
/>
</el-form-item>
<label class="custom-form-item-label" :class="'custom-form-item-label--' + themes"
>{{ t('chart.name') }}{{ t('chart.text') }}</label
>
<div style="display: flex">
<el-form-item
class="form-item"
:class="'form-item-' + themes"
v-if="showProperty('color')"
style="padding-right: 4px"
:label="t('chart.chart_style')"
>
<el-color-picker
v-model="state.axisForm.color"
@ -154,6 +152,7 @@ onMounted(() => {
v-if="showProperty('fontSize')"
style="padding-left: 4px"
>
<template #label>&nbsp;</template>
<el-tooltip content="字号" :effect="toolTip" placement="top">
<el-select
style="width: 108px"

View File

@ -4,9 +4,10 @@ import {
} from '@/views/chart/components/js/panel/types/impl/g2plot'
import { ScatterOptions, Scatter as G2Scatter } from '@antv/g2plot/esm/plots/scatter'
import { flow, parseJson } from '../../../util'
import { valueFormatter } from '../../../formatter'
import { valueFormatter } from '@/views/chart/components/js/formatter'
import { useI18n } from '@/hooks/web/useI18n'
import { isEmpty } from 'lodash-es'
import { isEmpty, map } from 'lodash-es'
import { cloneDeep, defaultTo } from 'lodash-es'
const { t } = useI18n()
/**
@ -119,58 +120,40 @@ export class Quadrant extends G2PlotChartView<ScatterOptions, G2Scatter> {
if (!chart.data?.data) {
return
}
const { colorFieldObj, sizeFieldObj, xFieldObj, yFieldObj } = this.getFieldObject(chart)
if (!xFieldObj.id || !yFieldObj.id || yFieldObj.id === xFieldObj.id) {
return
}
const data: any[] = []
// 根据指标字段对数据列表进行分组
const groupedData = chart.data?.data
?.filter(item => item['category'] != null)
.reduce((result, item) => {
;(result[item['field']] = result[item['field']] || []).push(item)
return result
}, {})
// 维度字段数据分组
chart.data?.data
?.filter(item => item['category'] === null)
.forEach(item => {
;(groupedData[colorFieldObj.name] = groupedData[colorFieldObj.name] || []).push(
item['field']
)
})
// 去掉groupedData每个key中集合的对象重复项
Object.keys(groupedData).forEach(key => {
groupedData[key] = Array.from(this.getUniqueObjects(groupedData[key]))
// data
const sourceData: Array<any> = cloneDeep(chart.data.data)
const data1 = defaultTo(sourceData[0]?.data, [])
const data2 = defaultTo(sourceData[1]?.data, [])
const data3 = defaultTo(sourceData[2]?.data, [])
const xData = data1.map(item => {
return {
...item,
id: item.quotaList[0]?.id,
field: item.field,
value: item.value
}
})
// 一个指标字段的数据长度视为数据长度也就是有多少数据
const dataLength = chart.data?.data.length / chart.data?.fields.length
for (let index = 0; index < dataLength; index++) {
const tmpData = {
dimensionList: groupedData[xFieldObj.name][index].dimensionList,
quotaList: groupedData[xFieldObj.name][index].quotaList,
[xFieldObj.name]: groupedData[xFieldObj.name][index].value
const yData = data2.map(item => {
return {
...item,
id: item.quotaList[0]?.id,
field: item.field,
value: item.value
}
if (groupedData[yFieldObj.name]) {
tmpData[yFieldObj.name] = groupedData[yFieldObj.name][index].value
})
const eData = data3.map(item => {
return {
...item,
id: item.quotaList[0]?.id,
field: item.field,
value: item.value
}
if (
groupedData[sizeFieldObj.name] &&
sizeFieldObj.name !== yFieldObj.name &&
sizeFieldObj.name !== xFieldObj.name
) {
tmpData[sizeFieldObj.name] = groupedData[sizeFieldObj.name]?.[index].value
}
if (groupedData[colorFieldObj.name]) {
tmpData[colorFieldObj.name] = groupedData[colorFieldObj.name][index]
}
data.push(tmpData)
}
})
// x轴基准线 默认值
const xValues = data.map(item => item[xFieldObj.name])
const xValues = xData.map(item => item.value)
const xBaseline = ((Math.max(...xValues) + Math.min(...xValues)) / 2).toFixed()
// y轴基准线 默认值
const yValues = data.map(item => item[yFieldObj.name])
const yValues = yData.map(item => item.value)
const yBaseline = ((Math.max(...yValues) + Math.min(...yValues)) / 2).toFixed()
const defaultBaselineQuadrant = {
...chart.customAttr['quadrant']
@ -181,15 +164,25 @@ export class Quadrant extends G2PlotChartView<ScatterOptions, G2Scatter> {
defaultBaselineQuadrant.xBaseline = xBaseline
defaultBaselineQuadrant.yBaseline = yBaseline
}
const colorField = colorFieldObj.name ? { colorField: colorFieldObj.name } : {}
const data = map(defaultTo(xData, []), d => {
return {
...d,
yAxis: d.value,
quotaList: d.quotaList
.concat(yData.find(item => item.field === d.field)?.quotaList)
.concat(eData.find(item => item.field === d.field)?.quotaList),
yAxisExt: yData.find(item => item.field === d.field)?.value,
extBubble: eData.find(item => item.field === d.field)?.value
}
})
const baseOptions: ScatterOptions = {
...colorField,
colorField: 'field',
quadrant: {
...defaultBaselineQuadrant
},
data: data,
xField: xFieldObj.name,
yField: yFieldObj.name,
xField: 'yAxis',
yField: 'yAxisExt',
appendPadding: 30,
pointStyle: {
fillOpacity: 0.8,
@ -208,12 +201,11 @@ export class Quadrant extends G2PlotChartView<ScatterOptions, G2Scatter> {
protected configBasicStyle(chart: Chart, options: ScatterOptions): ScatterOptions {
const customAttr = parseJson(chart.customAttr)
const basicStyle = customAttr.basicStyle
const extBubbleObj = { id: chart.extBubble[0]?.id, name: chart.extBubble[0]?.['originName'] }
if (chart.extBubble?.length) {
return {
...options,
size: [4, 30],
sizeField: extBubbleObj.name,
sizeField: 'extBubble',
shape: basicStyle.scatterSymbol
}
}
@ -296,7 +288,7 @@ export class Quadrant extends G2PlotChartView<ScatterOptions, G2Scatter> {
fontSize: l.fontSize
},
content: datum => {
return datum[chart.xAxis[0]?.['originName']]
return datum['name']
},
layout: [{ type: 'limit-in-shape' }]
}
@ -326,35 +318,47 @@ export class Quadrant extends G2PlotChartView<ScatterOptions, G2Scatter> {
pre[next['seriesId']] = next
return pre
}, {}) as Record<string, SeriesFormatter>
const optionsData = cloneDeep(options.data)
const tooltip: ScatterOptions['tooltip'] = {
showTitle: true,
title: (_title, datum) => {
return datum?.[xAxisTitle['originName']]
return datum?.['name']
},
customItems(originalItems) {
if (!tooltipAttr.seriesTooltipFormatter?.length) {
return originalItems
}
const result = []
originalItems
?.filter(i => i.name !== xAxisTitle['originName'])
.forEach(item => {
Object.keys(formatterMap).forEach(key => {
if (formatterMap[key]['originName'] === item.name) {
const formatter = formatterMap[key]
if (formatter) {
const value =
formatter.groupType === 'q'
? valueFormatter(parseFloat(item.value as string), formatter.formatterCfg)
: item.value
const name = isEmpty(formatter.chartShowName)
? formatter.name
: formatter.chartShowName
result.push({ color: item.color, name, value })
}
originalItems.forEach(item => {
Object.keys(formatterMap).forEach(key => {
if (key.endsWith(item.name)) {
const formatter = formatterMap[key]
if (formatter) {
const value =
formatter.groupType === 'q'
? valueFormatter(parseFloat(item.value as string), formatter.formatterCfg)
: item.value
const name = isEmpty(formatter.chartShowName)
? formatter.name
: formatter.chartShowName
result.push({ color: item.color, name, value })
}
})
}
})
})
const dynamicTooltipValue = optionsData.find(
d => d.field === originalItems[0]['title']
)?.dynamicTooltipValue
if (dynamicTooltipValue.length > 0) {
dynamicTooltipValue.forEach(dy => {
const q = tooltipAttr.seriesTooltipFormatter.filter(i => i.id === dy.fieldId)
if (q && q.length > 0) {
const value = valueFormatter(parseFloat(dy.value as string), q[0].formatterCfg)
const name = isEmpty(q[0].chartShowName) ? q[0].name : q[0].chartShowName
result.push({ color: 'grey', name, value })
}
})
}
return result
}
}