diff --git a/core/frontend/src/lang/en.js b/core/frontend/src/lang/en.js index 60fbf8b68c..d9107a87b7 100644 --- a/core/frontend/src/lang/en.js +++ b/core/frontend/src/lang/en.js @@ -1488,6 +1488,8 @@ export default { label_content: 'Label Content', percent: 'Percent', table_index_desc: 'Index Header Name', + table_row_tooltip: 'Row Tooltip', + table_col_tooltip: 'Column Tooltip', total_sort: 'Total Sort', total_sort_none: 'None', total_sort_asc: 'ASC', diff --git a/core/frontend/src/lang/tw.js b/core/frontend/src/lang/tw.js index d09ad5b60b..46f81309e5 100644 --- a/core/frontend/src/lang/tw.js +++ b/core/frontend/src/lang/tw.js @@ -1487,6 +1487,8 @@ export default { label_content: '標籤展示', percent: '占比', table_index_desc: '表頭名稱', + table_row_tooltip: '行頭提示', + table_col_tooltip: '列頭提示', total_sort: '總計排序', total_sort_none: '無', total_sort_asc: '升序', diff --git a/core/frontend/src/lang/zh.js b/core/frontend/src/lang/zh.js index ec9e6a5618..9caef8aa21 100644 --- a/core/frontend/src/lang/zh.js +++ b/core/frontend/src/lang/zh.js @@ -1486,6 +1486,8 @@ export default { label_content: '标签展示', percent: '占比', table_index_desc: '表头名称', + table_row_tooltip: '行头提示', + table_col_tooltip: '列头提示', total_sort: '总计排序', total_sort_none: '无', total_sort_asc: '升序', diff --git a/core/frontend/src/main.js b/core/frontend/src/main.js index 8081fd0d2b..dc12881242 100644 --- a/core/frontend/src/main.js +++ b/core/frontend/src/main.js @@ -40,6 +40,7 @@ import VueFriendlyIframe from 'vue-friendly-iframe' import vueToPdf from 'vue-to-pdf' import VueVideoPlayer from 'vue-video-player' import 'video.js/dist/video-js.css' +import '@antv/s2/dist/style.min.css' // 控制标签宽高成比例的指令 import proportion from 'vue-proportion-directive' diff --git a/core/frontend/src/views/chart/chart/chart.js b/core/frontend/src/views/chart/chart/chart.js index 1af8b92939..9028a31522 100644 --- a/core/frontend/src/views/chart/chart/chart.js +++ b/core/frontend/src/views/chart/chart/chart.js @@ -86,6 +86,12 @@ export const DEFAULT_SIZE = { tableHeaderAlign: 'left', tableItemAlign: 'right', tableAutoBreakLine: false, + tableRowTooltip: { + show: false + }, + tableColTooltip: { + show: false + }, gaugeMinType: 'fix', // fix or dynamic gaugeMinField: { id: '', diff --git a/core/frontend/src/views/chart/chart/table/table-info.js b/core/frontend/src/views/chart/chart/table/table-info.js index 4f262bf81e..37f026b1b6 100644 --- a/core/frontend/src/views/chart/chart/table/table-info.js +++ b/core/frontend/src/views/chart/chart/table/table-info.js @@ -1,4 +1,4 @@ -import { TableSheet, S2Event, PivotSheet, DataCell, EXTRA_FIELD, TOTAL_VALUE } from '@antv/s2' +import { TableSheet, S2Event, PivotSheet, DataCell, EXTRA_FIELD, TOTAL_VALUE, BaseEvent } from '@antv/s2' 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' @@ -7,7 +7,7 @@ export function baseTableInfo(s2, container, chart, action, tableData, pageInfo) const containerDom = document.getElementById(container) // fields - const fields = chart.data.fields + let fields = chart.data.fields if (!fields || fields.length === 0) { if (s2) { s2.destroy() @@ -17,8 +17,17 @@ export function baseTableInfo(s2, container, chart, action, tableData, pageInfo) const columns = [] const meta = [] - - // add drill list + // 记录下钻起始字段的index + let xAxis = [] + try { + xAxis = JSON.parse(chart.xaxis) + } catch (err) { + xAxis = JSON.parse(JSON.stringify(chart.xaxis)) + } + const nameMap = xAxis.reduce((pre, next) => { + pre[next.dataeaseName] = next + return pre + }, {}) if (chart.drill) { let drillFields = [] try { @@ -26,107 +35,44 @@ export function baseTableInfo(s2, container, chart, action, tableData, pageInfo) } catch (err) { drillFields = JSON.parse(JSON.stringify(chart.drillFields)) } - - const drillField = drillFields[chart.drillFilters.length] - - const drillFilters = JSON.parse(JSON.stringify(chart.drillFilters)) - const drillExp = drillFilters[drillFilters.length - 1].datasetTableField - - // 记录下钻起始字段的index - let xAxis = [] - try { - xAxis = JSON.parse(chart.xaxis) - } catch (err) { - xAxis = JSON.parse(JSON.stringify(chart.xaxis)) - } - let index = 0 - for (let i = 0; i < xAxis.length; i++) { - if (xAxis[i].id === drillFilters[0].fieldId) { - index = i - break - } - } - - // 移除所有下钻字段 - const removeField = [] - for (let i = 0; i < chart.drillFilters.length; i++) { - const ele = chart.drillFilters[i].datasetTableField - removeField.push(ele.dataeaseName) - } - - // build field - fields.forEach(ele => { - if (removeField.indexOf(ele.dataeaseName) < 0) { - // 用下钻字段替换当前字段 - if (drillExp.dataeaseName === ele.dataeaseName) { - columns.push(drillField.dataeaseName) - meta.push({ - field: drillField.dataeaseName, - name: drillField.name - }) - } else { - const f = getCurrentField(chart.xaxis, ele) - columns.push(ele.dataeaseName) - meta.push({ - field: ele.dataeaseName, - name: ele.name, - formatter: function(value) { - if (!f) { - return value - } - if (value === null || value === undefined) { - return value - } - if (f.groupType === 'd') { - return value - } else { - if (f.formatterCfg) { - const v = valueFormatter(value, f.formatterCfg) - return v.includes('NaN') ? value : v - } else { - const v = valueFormatter(value, formatterItem) - return v.includes('NaN') ? value : v - } - } - } - }) - } - } - }) - - // 修正下钻字段的index,获取下钻位置元素添加到index位置,并删除 - const ele = columns[columns.length - 1] - columns.splice(index, 0, ele) - columns.splice(columns.length - 1, 1) - } else { - fields.forEach(ele => { - const f = getCurrentField(chart.xaxis, ele) - columns.push(ele.dataeaseName) - meta.push({ - field: ele.dataeaseName, - name: ele.name, - formatter: function(value) { - if (!f) { - return value - } - if (value === null || value === undefined) { - return value - } - if (f.groupType === 'd') { - return value - } else { - if (f.formatterCfg) { - const v = valueFormatter(value, f.formatterCfg) - return v.includes('NaN') ? value : v - } else { - const v = valueFormatter(value, formatterItem) - return v.includes('NaN') ? value : v - } - } - } - }) - }) + // 总下钻过滤字段 + const drillFilters = JSON.parse(JSON.stringify(chart.drillFilters)).map(i => i.fieldId) + // 当前下钻字段 + const curDrillField = drillFields[chart.drillFilters.length] + drillFilters.push(curDrillField.id) + // 下钻入口字段的下标 + const drillEnterFieldIndex = xAxis.findIndex(item => item.id === drillFilters[0]) + // 移除所有下钻字段,调整当前下钻字段到下钻入口位置 + fields = fields.filter(item => !drillFilters.includes(item.id)) + fields.splice(drillEnterFieldIndex, 0, curDrillField) } + fields.forEach(ele => { + const f = nameMap[ele.dataeaseName] + columns.push(ele.dataeaseName) + meta.push({ + field: ele.dataeaseName, + name: ele.name, + formatter: function(value) { + if (!f) { + return value + } + if (value === null || value === undefined) { + return value + } + if (f.groupType === 'd') { + return value + } else { + if (f.formatterCfg) { + const v = valueFormatter(value, f.formatterCfg) + return v.includes('NaN') ? value : v + } else { + const v = valueFormatter(value, formatterItem) + return v.includes('NaN') ? value : v + } + } + } + }) + }) // 空值处理 const newData = handleTableEmptyStrategy(tableData, chart) // data config @@ -174,6 +120,11 @@ export function baseTableInfo(s2, container, chart, action, tableData, pageInfo) // click s2.on(S2Event.DATA_CELL_CLICK, action) + // hover + const size = customAttr.size + if (size.tableColTooltip?.show) { + s2.on(S2Event.COL_CELL_HOVER, event => showTooltip(s2, event)) + } // theme const customTheme = getCustomTheme(chart) @@ -342,7 +293,11 @@ export function baseTableNormal(s2, container, chart, action, tableData) { // click s2.on(S2Event.DATA_CELL_CLICK, action) - + // hover + const size = customAttr.size + if (size.tableColTooltip?.show) { + s2.on(S2Event.COL_CELL_HOVER, event => showTooltip(s2, event)) + } // theme const customTheme = getCustomTheme(chart) s2.setThemeCfg({ theme: customTheme }) @@ -455,8 +410,8 @@ export function baseTablePivot(s2, container, chart, action, headerAction, table // total config let totalCfg = {} const chartObj = JSON.parse(JSON.stringify(chart)) + let customAttr if (chartObj.customAttr) { - let customAttr = null if (Object.prototype.toString.call(chartObj.customAttr) === '[object Object]') { customAttr = JSON.parse(JSON.stringify(chartObj.customAttr)) } else { @@ -528,7 +483,14 @@ export function baseTablePivot(s2, container, chart, action, headerAction, table s2.on(S2Event.DATA_CELL_CLICK, action) s2.on(S2Event.ROW_CELL_CLICK, headerAction) s2.on(S2Event.COL_CELL_CLICK, headerAction) - + // hover + const size = customAttr?.size + if (size?.tableRowTooltip?.show) { + s2.on(S2Event.ROW_CELL_HOVER, event => showTooltip(s2, event)) + } + if (size?.tableColTooltip?.show) { + s2.on(S2Event.COL_CELL_HOVER, event => showTooltip(s2, event)) + } // theme const customTheme = getCustomTheme(chart) s2.setThemeCfg({ theme: customTheme }) @@ -740,3 +702,17 @@ function mappingColor(value, defaultColor, field, type) { } return color } + +function showTooltip(s2Instance, event) { + const cell = s2Instance.getCell(event.target) + const meta = cell.getMeta() + const content = meta.value + + s2Instance.showTooltip({ + position: { + x: event.clientX, + y: event.clientY + }, + content + }) +} diff --git a/core/frontend/src/views/chart/chart/util.js b/core/frontend/src/views/chart/chart/util.js index fdacc429a7..cbde5bcffd 100644 --- a/core/frontend/src/views/chart/chart/util.js +++ b/core/frontend/src/views/chart/chart/util.js @@ -62,7 +62,8 @@ export const TYPE_CONFIGS = [ 'tableItemHeight', 'tableColumnMode', 'showIndex', - 'indexLabel' + 'indexLabel', + 'tableColTooltip' ], 'title-selector-ant-v': [ 'show', @@ -111,7 +112,8 @@ export const TYPE_CONFIGS = [ 'tableItemHeight', 'tableColumnMode', 'showIndex', - 'indexLabel' + 'indexLabel', + 'tableColTooltip' ], 'title-selector-ant-v': [ 'show', @@ -157,7 +159,9 @@ export const TYPE_CONFIGS = [ 'tableItemAlign', 'tableTitleHeight', 'tableItemHeight', - 'tableColumnMode' + 'tableColumnMode', + 'tableRowTooltip', + 'tableColTooltip' ], 'total-cfg': [ 'row', diff --git a/core/frontend/src/views/chart/components/ChartComponentS2.vue b/core/frontend/src/views/chart/components/ChartComponentS2.vue index 31d5e3ca22..66597743cd 100644 --- a/core/frontend/src/views/chart/components/ChartComponentS2.vue +++ b/core/frontend/src/views/chart/components/ChartComponentS2.vue @@ -613,3 +613,8 @@ export default { background: transparent !important; } + diff --git a/core/frontend/src/views/chart/components/shapeAttr/SizeSelectorAntV.vue b/core/frontend/src/views/chart/components/shapeAttr/SizeSelectorAntV.vue index bbb8916efa..92b4155b21 100644 --- a/core/frontend/src/views/chart/components/shapeAttr/SizeSelectorAntV.vue +++ b/core/frontend/src/views/chart/components/shapeAttr/SizeSelectorAntV.vue @@ -384,6 +384,28 @@ @blur="changeBarSizeCase('indexLabel')" /> + + + + + + @@ -1565,6 +1587,8 @@ export default { this.sizeForm.tableHeaderAlign = this.sizeForm.tableHeaderAlign ? this.sizeForm.tableHeaderAlign : DEFAULT_SIZE.tableHeaderAlign this.sizeForm.tableItemAlign = this.sizeForm.tableItemAlign ? this.sizeForm.tableItemAlign : DEFAULT_SIZE.tableItemAlign + this.sizeForm.tableRowTooltip = this.sizeForm.tableRowTooltip ?? DEFAULT_SIZE.tableRowTooltip + this.sizeForm.tableColTooltip = this.sizeForm.tableColTooltip ?? DEFAULT_SIZE.tableColTooltip this.sizeForm.showIndex = this.sizeForm.showIndex ? this.sizeForm.showIndex : DEFAULT_SIZE.showIndex if (this.sizeForm.indexLabel === null || this.sizeForm.indexLabel === undefined) {