From d7ded2e5af5aabda6a63556831f5c892f1623c32 Mon Sep 17 00:00:00 2001 From: wisonic-s Date: Thu, 25 May 2023 18:56:31 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E8=A7=86=E5=9B=BE-=E5=9C=B0=E5=9B=BE?= =?UTF-8?q?=EF=BC=8C=E6=B1=87=E6=80=BB=E8=A1=A8):=20ECharts=20=E5=9C=B0?= =?UTF-8?q?=E5=9B=BE=EF=BC=8CAntV=20=E6=B1=87=E6=80=BB=E8=A1=A8=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E7=A9=BA=E5=80=BC=E8=BF=87=E6=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://www.tapd.cn/55578866/prong/stories/view/1155578866001011957 --- frontend/src/lang/en.js | 1 + frontend/src/lang/tw.js | 1 + frontend/src/lang/zh.js | 1 + frontend/src/views/chart/chart/chart.js | 3 +- frontend/src/views/chart/chart/map/map.js | 18 ++++-- .../src/views/chart/chart/table/table-info.js | 6 +- frontend/src/views/chart/chart/util.js | 35 +++++++++++ .../views/chart/components/ChartComponent.vue | 2 +- .../chart/components/senior/FunctionCfg.vue | 62 +++++++++++++++++-- frontend/src/views/chart/view/ChartEdit.vue | 5 +- 10 files changed, 118 insertions(+), 16 deletions(-) diff --git a/frontend/src/lang/en.js b/frontend/src/lang/en.js index 533bf9b5ee..c6b4eb561e 100644 --- a/frontend/src/lang/en.js +++ b/frontend/src/lang/en.js @@ -1489,6 +1489,7 @@ export default { total_sort_desc: 'DESC', total_sort_field: 'Sort Field', empty_data_strategy: 'Empty Data Strategy', + empty_data_field_ctrl: 'Field Control', break_line: 'Keep', set_zero: 'Set Zero', ignore_data: 'Hide Data', diff --git a/frontend/src/lang/tw.js b/frontend/src/lang/tw.js index 209d78504a..d3a421ef11 100644 --- a/frontend/src/lang/tw.js +++ b/frontend/src/lang/tw.js @@ -1491,6 +1491,7 @@ export default { break_line: '保持為空', set_zero: '置為0', ignore_data: '隱藏空值', + empty_data_field_ctrl: '字段設置', sub_dimension_tip: '該字段為必填項,且不應使用類別軸中的字段,若無需該字段,請選擇基礎圖表進行展示,否則展示效果不理想', drill_dimension_tip: '鑽取字段僅支持數據集中的字段', table_scroll_tip: '明細表僅在分頁模式為"下拉"時生效。', diff --git a/frontend/src/lang/zh.js b/frontend/src/lang/zh.js index 6916b2234a..69525742ad 100644 --- a/frontend/src/lang/zh.js +++ b/frontend/src/lang/zh.js @@ -1487,6 +1487,7 @@ export default { total_sort_desc: '降序', total_sort_field: '排序字段', empty_data_strategy: '空值处理', + empty_data_field_ctrl: '字段设置', break_line: '保持为空', set_zero: '置为0', ignore_data: '隐藏空值', diff --git a/frontend/src/views/chart/chart/chart.js b/frontend/src/views/chart/chart/chart.js index 118cb83554..83f6f1e9f6 100644 --- a/frontend/src/views/chart/chart/chart.js +++ b/frontend/src/views/chart/chart/chart.js @@ -467,7 +467,8 @@ export const DEFAULT_FUNCTION_CFG = { sliderBg: '#FFFFFF', sliderFillBg: '#BCD6F1', sliderTextClolor: '#999999', - emptyDataStrategy: 'breakLine' + emptyDataStrategy: 'breakLine', + emptyDataFieldCtrl: [] } export const DEFAULT_THRESHOLD = { gaugeThreshold: '', diff --git a/frontend/src/views/chart/chart/map/map.js b/frontend/src/views/chart/chart/map/map.js index 4355229fb5..1d534f9a9e 100644 --- a/frontend/src/views/chart/chart/map/map.js +++ b/frontend/src/views/chart/chart/map/map.js @@ -38,7 +38,7 @@ const fillGradientColor = (data, colors) => { }) return data } -export function baseMapOption(chart_option, chart, themeStyle, curAreaCode, seriesId) { +export function baseMapOption(chart_option, geoJson, chart, themeStyle, curAreaCode, seriesId) { // 处理shape attr let customAttr = {} let isGradient = false @@ -151,18 +151,16 @@ export function baseMapOption(chart_option, chart, themeStyle, curAreaCode, seri if (senior) { senior = JSON.parse(senior) } - // 空值处理,echarts 对于值为 null 的默认策略是不展示,也就是保持为空,所以只需要处理忽略数据和置为 0 就行 - // 隐藏和不展示的区别是隐藏不会参与颜色分布的计算,而不展示会参与颜色计算 + // 空值处理,echarts 对于值为 null 的默认策略是不展示,也就是保持为空,所以只需要处理置为 0 就行 let emptyDataStrategy = senior?.functionCfg?.emptyDataStrategy if (!emptyDataStrategy) { emptyDataStrategy = 'breakLine' } + const subArea = new Set(geoJson.features.map(item => item.properties.name)) for (let i = 0; i < valueArr.length; i++) { const y = valueArr[i] - if (y.value === null && emptyDataStrategy === 'ignoreData') { - continue - } y.name = chart.data.x[i] + subArea.delete(y.name) if (y.value === null && emptyDataStrategy === 'setZero') { const tmp = _.clone(y) tmp.value = 0 @@ -171,6 +169,14 @@ export function baseMapOption(chart_option, chart, themeStyle, curAreaCode, seri } chart_option.series[0].data.push(y) } + if (emptyDataStrategy === 'setZero' && subArea.size > 0) { + subArea.forEach(item => { + chart_option.series[0].data.push({ + name: item, + value: 0 + }) + }) + } if (isGradient) { chart_option.series[0].data = fillGradientColor(chart_option.series[0].data, customAttr.color.colors) diff --git a/frontend/src/views/chart/chart/table/table-info.js b/frontend/src/views/chart/chart/table/table-info.js index 321f6398d0..f128be1d5c 100644 --- a/frontend/src/views/chart/chart/table/table-info.js +++ b/frontend/src/views/chart/chart/table/table-info.js @@ -2,7 +2,7 @@ import { TableSheet, S2Event, PivotSheet, DataCell, EXTRA_FIELD, TOTAL_VALUE } f import { getCustomTheme, getSize } from '@/views/chart/chart/common/common_table' import { DEFAULT_COLOR_CASE, DEFAULT_TOTAL } from '@/views/chart/chart/chart' import { formatterItem, valueFormatter } from '@/views/chart/chart/formatter' -import { hexColorToRGBA } from '@/views/chart/chart/util' +import { handleTableEmptyStrategy, hexColorToRGBA } from '@/views/chart/chart/util' export function baseTableInfo(s2, container, chart, action, tableData, pageInfo) { const containerDom = document.getElementById(container) @@ -300,13 +300,15 @@ export function baseTableNormal(s2, container, chart, action, tableData) { }) } + // 空值处理 + const newData = handleTableEmptyStrategy(tableData, chart) // data config const s2DataConfig = { fields: { columns: columns }, meta: meta, - data: tableData + data: newData } const customAttr = JSON.parse(chart.customAttr) diff --git a/frontend/src/views/chart/chart/util.js b/frontend/src/views/chart/chart/util.js index dfd14592a0..52ad0e780b 100644 --- a/frontend/src/views/chart/chart/util.js +++ b/frontend/src/views/chart/chart/util.js @@ -3690,3 +3690,38 @@ export function resetRgbOpacity(sourceColor, times) { } return sourceColor } + +export function handleTableEmptyStrategy(tableData, chart) { + let newData = tableData + let intersection = [] + let senior = chart.senior + if (senior) { + senior = JSON.parse(senior) + } + let emptyDataStrategy = senior?.functionCfg?.emptyDataStrategy + if (!emptyDataStrategy) { + emptyDataStrategy = 'breakLine' + } + const emptyDataFieldCtrl = senior?.functionCfg?.emptyDataFieldCtrl + if (emptyDataStrategy !== 'breakLine' && emptyDataFieldCtrl?.length && tableData?.length) { + const deNames = _.keys(tableData[0]) + intersection = _.intersection(deNames, emptyDataFieldCtrl) + } + if (intersection.length) { + newData = _.clone(tableData) + for (let i = 0; i < newData.length; i++) { + for (let j = 0, tmp = intersection.length; j < tmp; j++) { + const deName = intersection[j] + if (newData[i][deName] === null) { + if (emptyDataStrategy === 'setZero') { + newData[i][deName] = 0 + } + if (emptyDataStrategy === 'ignoreData') { + newData = _.filter(newData, (_, index) => index !== i) + } + } + } + } + } + return newData +} diff --git a/frontend/src/views/chart/components/ChartComponent.vue b/frontend/src/views/chart/components/ChartComponent.vue index 9d7bbbb614..a591aad8c0 100644 --- a/frontend/src/views/chart/components/ChartComponent.vue +++ b/frontend/src/views/chart/components/ChartComponent.vue @@ -439,7 +439,7 @@ export default { this.buttonTextColor = null } } - const chart_option = baseMapOption(base_json, chart, this.buttonTextColor, curAreaCode, this.currentSeriesId) + const chart_option = baseMapOption(base_json, geoJson, chart, this.buttonTextColor, curAreaCode, this.currentSeriesId) this.myEcharts(chart_option) const opt = this.myChart.getOption() if (opt && opt.series) { diff --git a/frontend/src/views/chart/components/senior/FunctionCfg.vue b/frontend/src/views/chart/components/senior/FunctionCfg.vue index d026f3018d..3fb9067d0e 100644 --- a/frontend/src/views/chart/components/senior/FunctionCfg.vue +++ b/frontend/src/views/chart/components/senior/FunctionCfg.vue @@ -80,9 +80,32 @@ > {{ $t('chart.break_line') }} {{ $t('chart.set_zero') }} - {{ $t('chart.ignore_data') }} + + {{ $t('chart.ignore_data') }} + + + + + + @@ -103,7 +126,8 @@ export default { data() { return { functionForm: JSON.parse(JSON.stringify(DEFAULT_FUNCTION_CFG)), - predefineColors: COLOR_PANEL + predefineColors: COLOR_PANEL, + fieldOptions: [] } }, computed: { @@ -111,8 +135,18 @@ export default { return this.chart.type !== 'bidirectional-bar' && !equalsAny(this.chart.type, 'map') }, showEmptyStrategy() { - return (this.chart.render === 'antv' && includesAny(this.chart.type, 'line', 'bar', 'area')) || - this.chart.render === 'echarts' && equalsAny(this.chart.type, 'map') + return (this.chart.render === 'antv' && + (includesAny(this.chart.type, 'line', 'bar', 'area') || + equalsAny(this.chart.type, 'table-normal'))) || + (this.chart.render === 'echarts' && equalsAny(this.chart.type, 'map')) + }, + showIgnoreOption() { + return !equalsAny(this.chart.type, 'map') + }, + showEmptyDataFieldCtrl() { + return this.showEmptyStrategy && + this.functionForm.emptyDataStrategy !== 'breakLine' && + equalsAny(this.chart.type, 'table-normal') } }, watch: { @@ -140,6 +174,26 @@ export default { } else { this.functionForm = JSON.parse(JSON.stringify(DEFAULT_FUNCTION_CFG)) } + this.initFieldCtrl() + } + }, + initFieldCtrl() { + if (this.showEmptyDataFieldCtrl) { + this.fieldOptions = [] + let yAxis = [] + if (Object.prototype.toString.call(this.chart.xaxis) === '[object Array]') { + yAxis = this.chart.yaxis + } else { + yAxis = JSON.parse(this.chart.yaxis) + } + if (this.chart.type === 'table-normal') { + yAxis.forEach(item => { + this.fieldOptions.push({ + label: item.name, + value: item.dataeaseName + }) + }) + } } }, changeFunctionCfg() { diff --git a/frontend/src/views/chart/view/ChartEdit.vue b/frontend/src/views/chart/view/ChartEdit.vue index 41f23cefa9..85578967d1 100644 --- a/frontend/src/views/chart/view/ChartEdit.vue +++ b/frontend/src/views/chart/view/ChartEdit.vue @@ -1955,11 +1955,12 @@ export default { equalsAny(this.view.type, 'text', 'label', 'map', 'buddle-map') }, showSeniorCfg() { - return includesAny(this.view.type, 'bar', 'line', 'area', 'mix') || + return includesAny(this.view.type, 'bar', 'line', 'area', 'mix', 'table') || equalsAny(this.view.type, 'table-normal', 'table-info', 'map') }, showFunctionCfg() { - return includesAny(this.view.type, 'bar', 'line', 'area', 'mix', 'map') + return includesAny(this.view.type, 'bar', 'line', 'area', 'mix', 'table') || + equalsAny(this.view.type, 'map') }, showScrollCfg() { return equalsAny(this.view.type, 'table-normal', 'table-info')