From 40da16013a988fe8c764eff179ecf78c9df02a97 Mon Sep 17 00:00:00 2001 From: limengnan <420004014@qq.com> Date: Tue, 1 Jul 2025 16:21:11 +0800 Subject: [PATCH] views\chart\components\js\panel --- .../editor/common/ChartTemplateInfo.vue | 109 +- .../components/editor/common/TemplateTips.vue | 76 + .../chart/components/editor/util/chart.ts | 76 +- .../editor/util/dataVisualization.ts | 3 +- .../components/js/panel/charts/bar/bar.ts | 121 +- .../js/panel/charts/bar/bidirectional-bar.ts | 20 +- .../js/panel/charts/bar/bullet-graph.ts | 507 ++++ .../js/panel/charts/bar/horizontal-bar.ts | 80 +- .../js/panel/charts/bar/progress-bar.ts | 44 +- .../js/panel/charts/bar/range-bar.ts | 47 +- .../js/panel/charts/bar/waterfall.ts | 3 +- .../components/js/panel/charts/line/area.ts | 9 +- .../js/panel/charts/line/dist/stock-line.js | 673 +++++ .../components/js/panel/charts/line/line.ts | 87 +- .../js/panel/charts/line/stock-line.ts | 35 +- .../js/panel/charts/liquid/liquid.ts | 2 +- .../js/panel/charts/map/bubble-map.ts | 3 +- .../components/js/panel/charts/map/common.ts | 23 + .../js/panel/charts/map/dist/flow-map.js | 391 +++ .../js/panel/charts/map/dist/symbolic-map.js | 632 +++++ .../panel/charts/map/dist/tooltip-carousel.js | 558 ++++ .../js/panel/charts/map/heat-map.ts | 14 +- .../components/js/panel/charts/map/map.ts | 28 +- .../js/panel/charts/map/symbolic-map.ts | 108 +- .../js/panel/charts/map/tooltip-carousel.ts | 12 +- .../js/panel/charts/others/chart-mix.ts | 45 +- .../js/panel/charts/others/circle-packing.ts | 8 +- .../js/panel/charts/others/gauge.ts | 8 +- .../js/panel/charts/others/indicator.ts | 3 +- .../js/panel/charts/others/quadrant.ts | 6 +- .../js/panel/charts/others/sankey.ts | 12 +- .../js/panel/charts/others/scatter.ts | 49 +- .../js/panel/charts/others/word-cloud.ts | 12 +- .../components/js/panel/charts/pie/pie.ts | 24 +- .../components/js/panel/charts/pie/rose.ts | 1 + .../js/panel/charts/table/common.ts | 1 + .../js/panel/charts/table/dist/t-heatmap.js | 402 +++ .../js/panel/charts/table/dist/table-info.js | 564 ++++ .../panel/charts/table/dist/table-normal.js | 356 +++ .../js/panel/charts/table/dist/table-pivot.js | 1278 +++++++++ .../js/panel/charts/table/t-heatmap.ts | 25 +- .../js/panel/charts/table/table-info.ts | 205 +- .../js/panel/charts/table/table-normal.ts | 118 +- .../js/panel/charts/table/table-pivot.ts | 429 ++- .../components/js/panel/common/common_antv.ts | 619 ++++- .../js/panel/common/common_table.ts | 592 +++- .../js/panel/common/dist/common_antv.js | 2404 ++++++++++++++++ .../js/panel/common/dist/common_table.js | 2442 +++++++++++++++++ .../components/js/panel/types/impl/g2plot.ts | 6 +- .../components/js/panel/types/impl/l7.ts | 4 +- .../components/js/panel/types/impl/s2.ts | 22 +- 51 files changed, 12630 insertions(+), 666 deletions(-) create mode 100644 frontend/src/data-visualization/chart/components/editor/common/TemplateTips.vue create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/bar/bullet-graph.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/line/dist/stock-line.js create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/map/dist/flow-map.js create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/map/dist/symbolic-map.js create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/map/dist/tooltip-carousel.js create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/table/dist/t-heatmap.js create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/table/dist/table-info.js create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/table/dist/table-normal.js create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/table/dist/table-pivot.js create mode 100644 frontend/src/data-visualization/chart/components/js/panel/common/dist/common_antv.js create mode 100644 frontend/src/data-visualization/chart/components/js/panel/common/dist/common_table.js diff --git a/frontend/src/data-visualization/chart/components/editor/common/ChartTemplateInfo.vue b/frontend/src/data-visualization/chart/components/editor/common/ChartTemplateInfo.vue index 8774c12..6c287a5 100644 --- a/frontend/src/data-visualization/chart/components/editor/common/ChartTemplateInfo.vue +++ b/frontend/src/data-visualization/chart/components/editor/common/ChartTemplateInfo.vue @@ -1,45 +1,98 @@ + + diff --git a/frontend/src/data-visualization/chart/components/editor/common/TemplateTips.vue b/frontend/src/data-visualization/chart/components/editor/common/TemplateTips.vue new file mode 100644 index 0000000..745cc55 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/editor/common/TemplateTips.vue @@ -0,0 +1,76 @@ + + + + diff --git a/frontend/src/data-visualization/chart/components/editor/util/chart.ts b/frontend/src/data-visualization/chart/components/editor/util/chart.ts index 22aa597..e861956 100644 --- a/frontend/src/data-visualization/chart/components/editor/util/chart.ts +++ b/frontend/src/data-visualization/chart/components/editor/util/chart.ts @@ -318,6 +318,32 @@ export const DEFAULT_MISC: ChartMiscAttr = { min: 0, max: 0, fieldId: undefined + }, + bullet: { + bar: { + ranges: { + fill: ['rgba(0,128,255,0.3)'], + size: 20, + showType: 'dynamic', + fixedRangeNumber: 3, + symbol: 'circle', + symbolSize: 4 + }, + measures: { + fill: ['rgba(0,128,255,1)'], + size: 15, + symbol: 'circle', + symbolSize: 4 + }, + target: { + fill: 'rgb(0,0,0)', + size: 20, + showType: 'dynamic', + value: 0, + symbol: 'line', + symbolSize: 4 + } + } } } @@ -453,7 +479,8 @@ export const DEFAULT_TABLE_HEADER: ChartTableHeaderAttr = { headerGroupConfig: { columns: [], meta: [] - } + }, + rowHeaderFreeze: true } export const DEFAULT_TABLE_CELL: ChartTableCellAttr = { tableFontColor: '#000000', @@ -552,17 +579,6 @@ export const DEFAULT_TITLE_STYLE_DARK = { remarkBackgroundColor: '#5A5C62' } -export const DEFAULT_LEGEND_STYLE: ChartLegendStyle = { - show: true, - hPosition: 'center', - vPosition: 'bottom', - orient: 'horizontal', - icon: 'circle', - color: '#333333', - fontSize: 12, - size: 4 -} - export const DEFAULT_LEGEND_STYLE_BASE: ChartLegendStyle = { show: true, hPosition: 'center', @@ -571,7 +587,24 @@ export const DEFAULT_LEGEND_STYLE_BASE: ChartLegendStyle = { icon: 'circle', color: '#333333', fontSize: 12, - size: 4 + size: 4, + showRange: true, + sort: 'none', + customSort: [] +} + +export const DEFAULT_LEGEND_STYLE: ChartLegendStyle = { + show: true, + hPosition: 'center', + vPosition: 'bottom', + orient: 'horizontal', + icon: 'circle', + color: '#333333', + fontSize: 12, + size: 4, + showRange: true, + sort: 'none', + customSort: [] } export const DEFAULT_LEGEND_STYLE_LIGHT: ChartLegendStyle = { @@ -634,6 +667,7 @@ export const DEFAULT_XAXIS_STYLE: ChartAxisStyle = { }, axisLabelFormatter: { type: 'auto', + unitLanguage: isEnLocal ? 'en' : 'ch', unit: 1, suffix: '', decimalCount: 2, @@ -680,6 +714,7 @@ export const DEFAULT_YAXIS_STYLE: ChartAxisStyle = { }, axisLabelFormatter: { type: 'auto', + unitLanguage: isEnLocal ? 'en' : 'ch', unit: 1, suffix: '', decimalCount: 2, @@ -724,6 +759,7 @@ export const DEFAULT_YAXIS_EXT_STYLE: ChartAxisStyle = { }, axisLabelFormatter: { type: 'auto', + unitLanguage: isEnLocal ? 'en' : 'ch', unit: 1, suffix: '', decimalCount: 2, @@ -1165,7 +1201,7 @@ export const CHART_FONT_FAMILY = [ { name: t('chart.font_family_kai_ti'), value: 'KaiTi' } ] -export const CHART_FONT_FAMILY_MAP:any = { +export const CHART_FONT_FAMILY_MAP = { 'Microsoft YaHei': 'Microsoft YaHei', SimSun: 'SimSun, "Songti SC", STSong', SimHei: 'SimHei, Helvetica', @@ -1395,6 +1431,13 @@ export const CHART_TYPE_CONFIGS = [ value: 'stock-line', title: t('chart.chart_stock_line'), icon: 'stock-line' + }, + { + render: 'antv', + category: 'compare', + value: 'bullet-graph', + title: t('chart.bullet_chart'), + icon: 'bullet-graph' } ] }, @@ -1651,6 +1694,7 @@ export const DEFAULT_BASIC_STYLE: ChartBasicStyle = { zoomButtonColor: '#aaa', zoomBackground: '#fff', tableLayoutMode: 'grid', + defaultExpandLevel: 1, calcTopN: false, topN: 5, topNLabel: t('datasource.other'), @@ -1679,7 +1723,9 @@ export const DEFAULT_BASIC_STYLE: ChartBasicStyle = { radarAreaColor: true, circleBorderColor: '#fff', circleBorderWidth: 0, - circlePadding: 0 + circlePadding: 0, + quotaPosition: 'col', + quotaColLabel: t('dataset.value') } export const BASE_VIEW_CONFIG = { diff --git a/frontend/src/data-visualization/chart/components/editor/util/dataVisualization.ts b/frontend/src/data-visualization/chart/components/editor/util/dataVisualization.ts index 93b6919..b8188db 100644 --- a/frontend/src/data-visualization/chart/components/editor/util/dataVisualization.ts +++ b/frontend/src/data-visualization/chart/components/editor/util/dataVisualization.ts @@ -1,5 +1,5 @@ export const VIEW_DETAILS_BASH_STYLE = - '{"id":"view-dialog-details-001","title":"图表明细","sceneId":0,"tableId":"1692381412250939392","type":"table-info","render":"antv","resultCount":1000,"resultMode":"all","refreshViewEnable":false,"refreshTime":5,"refreshUnit":"minute","xAxis":[{"id":"1692330126490","datasourceId":"1691734038709071872","datasetTableId":"7098147058204282880","datasetGroupId":"1692381412250939392","chartId":null,"originName":"月","name":"月","dbFieldName":null,"description":null,"dataeaseName":"f_dd62e53a9192cdf4","groupType":"d","type":"ANY","precision":null,"scale":null,"deType":0,"deExtractType":0,"extField":0,"checked":true,"columnIndex":null,"lastSyncTime":null,"dateFormat":null,"dateFormatType":null,"fieldShortName":"f_dd62e53a9192cdf4","summary":null,"sort":"none","dateStyle":"y_M_d","datePattern":"date_sub","chartType":null,"compareCalc":null,"logic":null,"filterType":null,"index":null,"formatterCfg":null,"chartShowName":null,"filter":[],"customSort":null,"busiType":null},{"id":"1692330126489","datasourceId":"1691734038709071872","datasetTableId":"7098147058204282880","datasetGroupId":"1692381412250939392","chartId":null,"originName":"年份","name":"年份","dbFieldName":null,"description":null,"dataeaseName":"f_190480c43bdda8df","groupType":"q","type":"BIGINT","precision":null,"scale":null,"deType":2,"deExtractType":2,"extField":0,"checked":true,"columnIndex":null,"lastSyncTime":null,"dateFormat":null,"dateFormatType":null,"fieldShortName":"f_190480c43bdda8df","summary":"sum","sort":"none","dateStyle":"y_M_d","datePattern":"date_sub","chartType":"bar","compareCalc":{"type":"none","resultData":"percent","field":null,"custom":null},"logic":null,"filterType":null,"index":null,"formatterCfg":{"type":"auto","unit":1,"suffix":"","decimalCount":2,"thousandSeparator":true},"chartShowName":null,"filter":[],"customSort":null,"busiType":null}],"xAxisExt":[],"yAxis":[],"yAxisExt":[],"extStack":[],"drillFields":[],"viewFields":[],"extBubble":[],"extLabel":[],"extTooltip":[],"customFilter":{},"customAttr":{"basicStyle":{"alpha":100,"tableBorderColor":"#E6E7E4","tableScrollBarColor":"#00000024","tableColumnMode":"adapt","tableColumnWidth":100,"tablePageMode":"pull","tablePageSize":20,"gaugeStyle":"default","colorScheme":"default","colors":["#5470c6","#91cc75","#fac858","#ee6666","#73c0de","#3ba272","#fc8452","#9a60b4","#ea7ccc"],"mapVendor":"amap","gradient":false,"lineWidth":2,"lineSymbol":"circle","lineSymbolSize":4,"lineSmooth":true,"barDefault":true,"barWidth":40,"barGap":0.4,"lineType":"solid","scatterSymbol":"circle","scatterSymbolSize":8,"radarShape":"polygon","mapStyle":"normal","areaBorderColor":"#303133","suspension":true,"areaBaseColor":"#FFFFFF","mapSymbolOpacity":0.7,"mapSymbolStrokeWidth":2,"mapSymbol":"circle","mapSymbolSize":20,"radius":100,"innerRadius":60},"misc":{"pieInnerRadius":0,"pieOuterRadius":80,"radarShape":"polygon","radarSize":80,"gaugeMinType":"fix","gaugeMinField":{"id":"","summary":""},"gaugeMin":0,"gaugeMaxType":"fix","gaugeMaxField":{"id":"","summary":""},"gaugeMax":100,"gaugeStartAngle":225,"gaugeEndAngle":-45,"nameFontSize":18,"valueFontSize":18,"nameValueSpace":10,"valueFontColor":"#5470c6","valueFontFamily":"Microsoft YaHei","valueFontIsBolder":false,"valueFontIsItalic":false,"valueLetterSpace":0,"valueFontShadow":false,"showName":true,"nameFontColor":"#000000","nameFontFamily":"Microsoft YaHei","nameFontIsBolder":false,"nameFontIsItalic":false,"nameLetterSpace":"0","nameFontShadow":false,"treemapWidth":80,"treemapHeight":80,"liquidMax":100,"liquidMaxType":"fix","liquidMaxField":{"id":"","summary":""},"liquidSize":80,"liquidShape":"circle","hPosition":"center","vPosition":"center","mapPitch":0,"mapLineType":"arc","mapLineWidth":1,"mapLineAnimateDuration":3,"mapLineGradient":false,"mapLineSourceColor":"#146C94","mapLineTargetColor":"#576CBC"},"label":{"show":false,"position":"top","color":"#000000","fontSize":10,"formatter":"","labelLine":{"show":true},"labelFormatter":{"type":"auto","unit":1,"suffix":"","decimalCount":2,"thousandSeparator":true},"reserveDecimalCount":2,"labelShadow":false,"labelBgColor":"","labelShadowColor":"","quotaLabelFormatter":{"type":"auto","unit":1,"suffix":"","decimalCount":2,"thousandSeparator":true},"showDimension":true,"showQuota":false,"showProportion":true,"seriesLabelFormatter":[]},"tooltip":{"show":true,"trigger":"item","confine":true,"fontSize":10,"color":"#000000","tooltipFormatter":{"type":"auto","unit":1,"suffix":"","decimalCount":2,"thousandSeparator":true},"backgroundColor":"#FFFFFF","seriesTooltipFormatter":[]},"tableTotal":{"row":{"showGrandTotals":true,"showSubTotals":true,"reverseLayout":false,"reverseSubLayout":false,"label":"总计","subLabel":"小计","subTotalsDimensions":[],"calcTotals":{"aggregation":"SUM"},"calcSubTotals":{"aggregation":"SUM"},"totalSort":"none","totalSortField":""},"col":{"showGrandTotals":true,"showSubTotals":true,"reverseLayout":false,"reverseSubLayout":false,"label":"总计","subLabel":"小计","subTotalsDimensions":[],"calcTotals":{"aggregation":"SUM"},"calcSubTotals":{"aggregation":"SUM"},"totalSort":"none","totalSortField":""}},"tableHeader":{"indexLabel":"序号","showIndex":false,"tableHeaderAlign":"left","tableHeaderBgColor":"#F5F6F7","tableHeaderFontColor":"#646A73","tableTitleFontSize":14,"tableTitleHeight":36},"tableCell":{"tableFontColor":"#1F2329","tableItemAlign":"right","tableItemBgColor":"#FFFFFF","tableItemFontSize":14,"tableItemHeight":36},"map":{"id":"","level":"world"}},"customStyle":{"text":{"show":false,"fontSize":"18","hPosition":"left","vPosition":"top","isItalic":false,"isBolder":true,"remarkShow":false,"remark":"","fontFamily":"Microsoft YaHei","letterSpace":"0","fontShadow":false,"color":"#000000","remarkBackgroundColor":"#ffffff"},"legend":{"show":true,"hPosition":"center","vPosition":"bottom","orient":"horizontal","icon":"circle","color":"#000000","fontSize":12},"xAxis":{"show":true,"position":"bottom","name":"","color":"#000000","fontSize":12,"axisLabel":{"show":true,"color":"#000000","fontSize":12,"rotate":0,"formatter":"{value}"},"axisLine":{"show":true,"lineStyle":{"color":"#cccccc","width":1,"style":"solid"}},"splitLine":{"show":false,"lineStyle":{"color":"#CCCCCC","width":1,"style":"solid"}},"axisValue":{"auto":true,"min":10,"max":100,"split":10,"splitCount":10},"axisLabelFormatter":{"type":"auto","unit":1,"suffix":"","decimalCount":2,"thousandSeparator":true}},"yAxis":{"show":true,"position":"left","name":"","color":"#000000","fontSize":12,"axisLabel":{"show":true,"color":"#000000","fontSize":12,"rotate":0,"formatter":"{value}"},"axisLine":{"show":false,"lineStyle":{"color":"#cccccc","width":1,"style":"solid"}},"splitLine":{"show":true,"lineStyle":{"color":"#CCCCCC","width":1,"style":"solid"}},"axisValue":{"auto":true,"min":10,"max":100,"split":10,"splitCount":10},"axisLabelFormatter":{"type":"auto","unit":1,"suffix":"","decimalCount":2,"thousandSeparator":true}},"yAxisExt":{"show":true,"position":"right","name":"","color":"#000000","fontSize":12,"axisLabel":{"show":true,"color":"#000000","fontSize":12,"rotate":0,"formatter":"{value}"},"axisLine":{"show":false,"lineStyle":{"color":"#cccccc","width":1,"style":"solid"}},"splitLine":{"show":true,"lineStyle":{"color":"#CCCCCC","width":1,"style":"solid"}},"axisValue":{"auto":true,"min":null,"max":null,"split":null,"splitCount":null},"axisLabelFormatter":{"type":"auto","unit":1,"suffix":"","decimalCount":2,"thousandSeparator":true}},"misc":{"showName":false,"color":"#000000","fontSize":12,"axisColor":"#999","splitNumber":5,"axisLine":{"show":true,"lineStyle":{"color":"#CCCCCC","width":1,"type":"solid"}},"axisTick":{"show":false,"length":5,"lineStyle":{"color":"#000000","width":1,"type":"solid"}},"axisLabel":{"show":false,"rotate":0,"margin":8,"color":"#000000","fontSize":"12","formatter":"{value}"},"splitLine":{"show":true,"lineStyle":{"color":"#CCCCCC","width":1,"type":"solid"}},"splitArea":{"show":true}}},"senior":{"functionCfg":{"sliderShow":false,"sliderRange":[0,10],"sliderBg":"#FFFFFF","sliderFillBg":"#BCD6F1","sliderTextColor":"#999999","emptyDataStrategy":"breakLine","emptyDataFieldCtrl":[]},"assistLine":[],"threshold":{"gaugeThreshold":"","labelThreshold":[],"tableThreshold":[],"textLabelThreshold":[]},"scrollCfg":{"open":false,"row":1,"interval":2000,"step":50}},"chartExtRequest":{"user":"1","filter":[],"drill":[],"resultCount":1000,"resultMode":"all"}}' + '{"id":"view-dialog-details-001","title":"图表明细","sceneId":0,"tableId":"1692381412250939392","type":"table-info","render":"antv","resultCount":1000,"resultMode":"all","refreshViewEnable":false,"refreshTime":5,"refreshUnit":"minute","xAxis":[{"id":"1692330126490","datasourceId":"1691734038709071872","datasetTableId":"7098147058204282880","datasetGroupId":"1692381412250939392","chartId":null,"originName":"月","name":"月","dbFieldName":null,"description":null,"gisbiName":"f_dd62e53a9192cdf4","groupType":"d","type":"ANY","precision":null,"scale":null,"deType":0,"deExtractType":0,"extField":0,"checked":true,"columnIndex":null,"lastSyncTime":null,"dateFormat":null,"dateFormatType":null,"fieldShortName":"f_dd62e53a9192cdf4","summary":null,"sort":"none","dateStyle":"y_M_d","datePattern":"date_sub","chartType":null,"compareCalc":null,"logic":null,"filterType":null,"index":null,"formatterCfg":null,"chartShowName":null,"filter":[],"customSort":null,"busiType":null},{"id":"1692330126489","datasourceId":"1691734038709071872","datasetTableId":"7098147058204282880","datasetGroupId":"1692381412250939392","chartId":null,"originName":"年份","name":"年份","dbFieldName":null,"description":null,"gisbiName":"f_190480c43bdda8df","groupType":"q","type":"BIGINT","precision":null,"scale":null,"deType":2,"deExtractType":2,"extField":0,"checked":true,"columnIndex":null,"lastSyncTime":null,"dateFormat":null,"dateFormatType":null,"fieldShortName":"f_190480c43bdda8df","summary":"sum","sort":"none","dateStyle":"y_M_d","datePattern":"date_sub","chartType":"bar","compareCalc":{"type":"none","resultData":"percent","field":null,"custom":null},"logic":null,"filterType":null,"index":null,"formatterCfg":{"type":"auto","unit":1,"suffix":"","decimalCount":2,"thousandSeparator":true},"chartShowName":null,"filter":[],"customSort":null,"busiType":null}],"xAxisExt":[],"yAxis":[],"yAxisExt":[],"extStack":[],"drillFields":[],"viewFields":[],"extBubble":[],"extLabel":[],"extTooltip":[],"customFilter":{},"customAttr":{"basicStyle":{"alpha":100,"tableBorderColor":"#E6E7E4","tableScrollBarColor":"#00000024","tableColumnMode":"adapt","tableColumnWidth":100,"tablePageMode":"pull","tablePageSize":20,"gaugeStyle":"default","colorScheme":"default","colors":["#5470c6","#91cc75","#fac858","#ee6666","#73c0de","#3ba272","#fc8452","#9a60b4","#ea7ccc"],"mapVendor":"amap","gradient":false,"lineWidth":2,"lineSymbol":"circle","lineSymbolSize":4,"lineSmooth":true,"barDefault":true,"barWidth":40,"barGap":0.4,"lineType":"solid","scatterSymbol":"circle","scatterSymbolSize":8,"radarShape":"polygon","mapStyle":"normal","areaBorderColor":"#303133","suspension":true,"areaBaseColor":"#FFFFFF","mapSymbolOpacity":0.7,"mapSymbolStrokeWidth":2,"mapSymbol":"circle","mapSymbolSize":20,"radius":100,"innerRadius":60},"misc":{"pieInnerRadius":0,"pieOuterRadius":80,"radarShape":"polygon","radarSize":80,"gaugeMinType":"fix","gaugeMinField":{"id":"","summary":""},"gaugeMin":0,"gaugeMaxType":"fix","gaugeMaxField":{"id":"","summary":""},"gaugeMax":100,"gaugeStartAngle":225,"gaugeEndAngle":-45,"nameFontSize":18,"valueFontSize":18,"nameValueSpace":10,"valueFontColor":"#5470c6","valueFontFamily":"Microsoft YaHei","valueFontIsBolder":false,"valueFontIsItalic":false,"valueLetterSpace":0,"valueFontShadow":false,"showName":true,"nameFontColor":"#000000","nameFontFamily":"Microsoft YaHei","nameFontIsBolder":false,"nameFontIsItalic":false,"nameLetterSpace":"0","nameFontShadow":false,"treemapWidth":80,"treemapHeight":80,"liquidMax":100,"liquidMaxType":"fix","liquidMaxField":{"id":"","summary":""},"liquidSize":80,"liquidShape":"circle","hPosition":"center","vPosition":"center","mapPitch":0,"mapLineType":"arc","mapLineWidth":1,"mapLineAnimateDuration":3,"mapLineGradient":false,"mapLineSourceColor":"#146C94","mapLineTargetColor":"#576CBC"},"label":{"show":false,"position":"top","color":"#000000","fontSize":10,"formatter":"","labelLine":{"show":true},"labelFormatter":{"type":"auto","unit":1,"suffix":"","decimalCount":2,"thousandSeparator":true},"reserveDecimalCount":2,"labelShadow":false,"labelBgColor":"","labelShadowColor":"","quotaLabelFormatter":{"type":"auto","unit":1,"suffix":"","decimalCount":2,"thousandSeparator":true},"showDimension":true,"showQuota":false,"showProportion":true,"seriesLabelFormatter":[]},"tooltip":{"show":true,"trigger":"item","confine":true,"fontSize":10,"color":"#000000","tooltipFormatter":{"type":"auto","unit":1,"suffix":"","decimalCount":2,"thousandSeparator":true},"backgroundColor":"#FFFFFF","seriesTooltipFormatter":[]},"tableTotal":{"row":{"showGrandTotals":true,"showSubTotals":true,"reverseLayout":false,"reverseSubLayout":false,"label":"总计","subLabel":"小计","subTotalsDimensions":[],"calcTotals":{"aggregation":"SUM"},"calcSubTotals":{"aggregation":"SUM"},"totalSort":"none","totalSortField":""},"col":{"showGrandTotals":true,"showSubTotals":true,"reverseLayout":false,"reverseSubLayout":false,"label":"总计","subLabel":"小计","subTotalsDimensions":[],"calcTotals":{"aggregation":"SUM"},"calcSubTotals":{"aggregation":"SUM"},"totalSort":"none","totalSortField":""}},"tableHeader":{"indexLabel":"序号","showIndex":false,"tableHeaderAlign":"left","tableHeaderBgColor":"#F5F6F7","tableHeaderFontColor":"#646A73","tableTitleFontSize":14,"tableTitleHeight":36},"tableCell":{"tableFontColor":"#1F2329","tableItemAlign":"right","tableItemBgColor":"#FFFFFF","tableItemFontSize":14,"tableItemHeight":36},"map":{"id":"","level":"world"}},"customStyle":{"text":{"show":false,"fontSize":"18","hPosition":"left","vPosition":"top","isItalic":false,"isBolder":true,"remarkShow":false,"remark":"","fontFamily":"Microsoft YaHei","letterSpace":"0","fontShadow":false,"color":"#000000","remarkBackgroundColor":"#ffffff"},"legend":{"show":true,"hPosition":"center","vPosition":"bottom","orient":"horizontal","icon":"circle","color":"#000000","fontSize":12},"xAxis":{"show":true,"position":"bottom","name":"","color":"#000000","fontSize":12,"axisLabel":{"show":true,"color":"#000000","fontSize":12,"rotate":0,"formatter":"{value}"},"axisLine":{"show":true,"lineStyle":{"color":"#cccccc","width":1,"style":"solid"}},"splitLine":{"show":false,"lineStyle":{"color":"#CCCCCC","width":1,"style":"solid"}},"axisValue":{"auto":true,"min":10,"max":100,"split":10,"splitCount":10},"axisLabelFormatter":{"type":"auto","unit":1,"suffix":"","decimalCount":2,"thousandSeparator":true}},"yAxis":{"show":true,"position":"left","name":"","color":"#000000","fontSize":12,"axisLabel":{"show":true,"color":"#000000","fontSize":12,"rotate":0,"formatter":"{value}"},"axisLine":{"show":false,"lineStyle":{"color":"#cccccc","width":1,"style":"solid"}},"splitLine":{"show":true,"lineStyle":{"color":"#CCCCCC","width":1,"style":"solid"}},"axisValue":{"auto":true,"min":10,"max":100,"split":10,"splitCount":10},"axisLabelFormatter":{"type":"auto","unit":1,"suffix":"","decimalCount":2,"thousandSeparator":true}},"yAxisExt":{"show":true,"position":"right","name":"","color":"#000000","fontSize":12,"axisLabel":{"show":true,"color":"#000000","fontSize":12,"rotate":0,"formatter":"{value}"},"axisLine":{"show":false,"lineStyle":{"color":"#cccccc","width":1,"style":"solid"}},"splitLine":{"show":true,"lineStyle":{"color":"#CCCCCC","width":1,"style":"solid"}},"axisValue":{"auto":true,"min":null,"max":null,"split":null,"splitCount":null},"axisLabelFormatter":{"type":"auto","unit":1,"suffix":"","decimalCount":2,"thousandSeparator":true}},"misc":{"showName":false,"color":"#000000","fontSize":12,"axisColor":"#999","splitNumber":5,"axisLine":{"show":true,"lineStyle":{"color":"#CCCCCC","width":1,"type":"solid"}},"axisTick":{"show":false,"length":5,"lineStyle":{"color":"#000000","width":1,"type":"solid"}},"axisLabel":{"show":false,"rotate":0,"margin":8,"color":"#000000","fontSize":"12","formatter":"{value}"},"splitLine":{"show":true,"lineStyle":{"color":"#CCCCCC","width":1,"type":"solid"}},"splitArea":{"show":true}}},"senior":{"functionCfg":{"sliderShow":false,"sliderRange":[0,10],"sliderBg":"#FFFFFF","sliderFillBg":"#BCD6F1","sliderTextColor":"#999999","emptyDataStrategy":"breakLine","emptyDataFieldCtrl":[]},"assistLine":[],"threshold":{"gaugeThreshold":"","labelThreshold":[],"tableThreshold":[],"textLabelThreshold":[]},"scrollCfg":{"open":false,"row":1,"interval":2000,"step":50}},"chartExtRequest":{"user":"1","filter":[],"drill":[],"resultCount":1000,"resultMode":"all"}}' import { DEFAULT_COLOR_CASE_DARK, @@ -61,6 +61,7 @@ export const MOBILE_SETTING_DARK = { export const DEFAULT_DASHBOARD_STYLE_BASE = { gap: 'yes', gapSize: 5, + gapMode: 'middle', showGrid: false, matrixBase: 4, // 当前matrix的基数 (是pcMatrixCount的几倍) resultMode: 'all', // 图表结果显示模式 all 图表 custom 仪表板自定义 diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/bar/bar.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/bar.ts index 3d25530..63d47cc 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/bar/bar.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/bar.ts @@ -7,7 +7,6 @@ import { import { flow, hexColorToRGBA, - hexToRgba, parseJson, setUpGroupSeriesColor, setUpStackSeriesColor @@ -21,6 +20,7 @@ import { } from '@/data-visualization/chart/components/js/panel/charts/bar/common' import { configPlotTooltipEvent, + configRoundAngle, getLabel, getPadding, getTooltipContainer, @@ -43,7 +43,14 @@ export class Bar extends G2PlotChartView { ...BAR_EDITOR_PROPERTY_INNER, 'basic-style-selector': [...BAR_EDITOR_PROPERTY_INNER['basic-style-selector'], 'seriesColor'], 'label-selector': ['vPosition', 'seriesLabelFormatter', 'showExtremum'], - 'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter', 'show'], + 'tooltip-selector': [ + 'fontSize', + 'color', + 'backgroundColor', + 'seriesTooltipFormatter', + 'show', + 'carousel' + ], 'y-axis-selector': [...BAR_EDITOR_PROPERTY_INNER['y-axis-selector'], 'axisLabelFormatter'] } protected baseOptions: ColumnOptions = { @@ -69,11 +76,14 @@ export class Bar extends G2PlotChartView { async drawChart(drawOptions: G2PlotDrawOptions): Promise { const { chart, container, action } = drawOptions + chart.container = container if (!chart?.data?.data?.length) { - chart.container = container clearExtremum(chart) return } + const isGroup = 'bar-group' === this.name && chart.xAxisExt?.length > 0 + const isStack = + ['bar-stack', 'bar-group-stack'].includes(this.name) && chart.extStack?.length > 0 const data = cloneDeep(drawOptions.chart.data?.data) const initOptions: ColumnOptions = { ...this.baseOptions, @@ -108,7 +118,7 @@ export class Bar extends G2PlotChartView { const label = { fields: [], ...tmpOptions.label, - formatter: (data: Datum, _point) => { + formatter: (data: Datum) => { if (data.EXTREME) { return '' } @@ -174,19 +184,9 @@ export class Bar extends G2PlotChartView { color } } - if (basicStyle.radiusColumnBar === 'roundAngle') { - const columnStyle = { - radius: [ - basicStyle.columnBarRightAngleRadius, - basicStyle.columnBarRightAngleRadius, - basicStyle.columnBarRightAngleRadius, - basicStyle.columnBarRightAngleRadius - ] - } - options = { - ...options, - columnStyle - } + options = { + ...options, + ...configRoundAngle(chart, 'columnStyle') } let columnWidthRatio const _v = basicStyle.columnWidthRatio ?? DEFAULT_BASIC_STYLE.columnWidthRatio @@ -227,7 +227,10 @@ export class Bar extends G2PlotChartView { tickCount: axisValue.splitCount } } - return { ...tmpOptions, ...axis } + // 根据axis的最小值,过滤options中的data数据,过滤掉小于最小值的数据 + const { data } = options + const newData = data.filter(item => item.value >= axisValue.min) + return { ...tmpOptions, data: newData, ...axis } } return tmpOptions } @@ -276,7 +279,14 @@ export class StackBar extends Bar { 'totalFormatter', 'showStackQuota' ], - 'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'tooltipFormatter', 'show'] + 'tooltip-selector': [ + 'fontSize', + 'color', + 'backgroundColor', + 'tooltipFormatter', + 'show', + 'carousel' + ] } protected configLabel(chart: Chart, options: ColumnOptions): ColumnOptions { let label = getLabel(chart) @@ -438,6 +448,74 @@ export class GroupBar extends StackBar { } } + async drawChart(drawOptions: G2PlotDrawOptions): Promise { + const plot = await super.drawChart(drawOptions) + if (!plot) { + return plot + } + const { chart } = drawOptions + const { xAxis, xAxisExt, yAxis } = chart + let innerSort = !!(xAxis.length && xAxisExt.length && yAxis.length) + if (innerSort && yAxis[0].sort === 'none') { + innerSort = false + } + if (innerSort && xAxisExt[0].sort !== 'none') { + const sortPriority = chart.sortPriority ?? [] + const yAxisIndex = sortPriority?.findIndex(e => e.id === yAxis[0].id) + const xAxisExtIndex = sortPriority?.findIndex(e => e.id === xAxisExt[0].id) + if (xAxisExtIndex <= yAxisIndex) { + innerSort = false + } + } + if (!innerSort) { + return plot + } + plot.chart.once('beforepaint', () => { + const geo = plot.chart.geometries[0] + const originMapping = geo.beforeMapping.bind(geo) + geo.beforeMapping = originData => { + const values = geo.getXScale().values + const valueMap = values.reduce((p, n) => { + if (!p?.[n]) { + p[n] = { + fieldArr: [], + indexArr: [], + dataArr: [] + } + } + originData.forEach((arr, arrIndex) => { + arr.forEach((item, index) => { + if (item._origin.field === n) { + p[n].fieldArr.push(item.field) + p[n].indexArr.push([arrIndex, index]) + p[n].dataArr.push(item) + } + }) + }) + return p + }, {}) + values.forEach(v => { + const item = valueMap[v] + item.dataArr.sort((a, b) => { + if (yAxis[0].sort === 'asc') { + return a.value - b.value + } + if (yAxis[0].sort === 'desc') { + return b.value - a.value + } + return 0 + }) + item.indexArr.forEach((index, i) => { + item.dataArr[i].field = item.fieldArr[i] + originData[index[0]][index[1]] = item.dataArr[i] + }) + }) + return originMapping(originData) + } + }) + return plot + } + protected configLabel(chart: Chart, options: ColumnOptions): ColumnOptions { const tmpLabel = getLabel(chart) if (!tmpLabel) { @@ -448,7 +526,7 @@ export class GroupBar extends StackBar { baseOptions.label.style.fill = labelAttr.color const label = { ...baseOptions.label, - formatter: function (param: Datum, _point) { + formatter: function (param: Datum) { if (param.EXTREME) { return '' } @@ -492,6 +570,7 @@ export class GroupBar extends StackBar { super(name) this.baseOptions = { ...this.baseOptions, + marginRatio: 0, isGroup: true, isStack: false, meta: { @@ -606,7 +685,7 @@ export class PercentageStackBar extends GroupStackBar { propertyInner = { ...this['propertyInner'], 'label-selector': ['color', 'fontSize', 'vPosition', 'reserveDecimalCount'], - 'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'show'] + 'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'show', 'carousel'] } protected configLabel(chart: Chart, options: ColumnOptions): ColumnOptions { const baseOptions = super.configLabel(chart, options) diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/bar/bidirectional-bar.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/bidirectional-bar.ts index 41456d0..d327265 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/bar/bidirectional-bar.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/bidirectional-bar.ts @@ -6,14 +6,14 @@ import { cloneDeep, defaultTo, isEmpty, map } from 'lodash-es' import { configAxisLabelLengthLimit, configPlotTooltipEvent, + configRoundAngle, getPadding, getTooltipContainer, getTooltipItemConditionColor, getYAxis, getYAxisExt, setGradientColor, - TOOLTIP_TPL, - addConditionsStyleColorToData + TOOLTIP_TPL } from '@/data-visualization/chart/components/js/panel/common/common_antv' import type { BidirectionalBar as G2BidirectionalBar, @@ -213,19 +213,9 @@ export class BidirectionalHorizontalBar extends G2PlotChartView< ...options, layout: basicStyle.layout } - if (basicStyle.radiusColumnBar === 'roundAngle') { - const barStyle = { - radius: [ - basicStyle.columnBarRightAngleRadius, - basicStyle.columnBarRightAngleRadius, - basicStyle.columnBarRightAngleRadius, - basicStyle.columnBarRightAngleRadius - ] - } - options = { - ...options, - barStyle - } + options = { + ...options, + ...configRoundAngle(chart, 'barStyle') } return options } diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/bar/bullet-graph.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/bullet-graph.ts new file mode 100644 index 0000000..66ea6de --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/bullet-graph.ts @@ -0,0 +1,507 @@ +import type { + Bullet as G2Bullet, + BulletOptions as G2BulletOptions +} from '@antv/g2plot/esm/plots/bullet' +import { + G2PlotChartView, + G2PlotDrawOptions +} from '@/data-visualization/chart/components/js/panel/types/impl/g2plot' +import { + BAR_AXIS_TYPE, + BAR_EDITOR_PROPERTY, + BAR_EDITOR_PROPERTY_INNER +} from '@/data-visualization/chart/components/js/panel/charts/bar/common' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { flow, parseJson } from '@/data-visualization/chart/components/js/util' +import { BulletOptions } from '@antv/g2plot' +import { isEmpty } from 'lodash-es' +import { + configAxisLabelLengthLimit, + configPlotTooltipEvent, + getPadding, + getTooltipContainer, + TOOLTIP_TPL +} from '@/data-visualization/chart/components/js/panel/common/common_antv' +import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' + +const { t } = useI18n() + +/** + * 子弹图 + */ +export class BulletGraph extends G2PlotChartView { + constructor() { + super('bullet-graph', []) + } + + axis: AxisType[] = [...BAR_AXIS_TYPE, 'yAxisExt', 'extBubble'] + axisConfig = { + ...this['axisConfig'], + xAxis: { name: `${t('chart.form_type')} / ${t('chart.dimension')}`, type: 'd', limit: 1 }, + yAxis: { name: `${t('chart.progress_current')} / ${t('chart.quota')}`, type: 'q', limit: 1 }, + yAxisExt: { name: `${t('chart.progress_target')} / ${t('chart.quota')}`, type: 'q', limit: 1 }, + extBubble: { + name: `${t('chart.range_bg')} / ${t('chart.quota')}`, + type: 'q', + allowEmpty: true, + limit: 1 + } + } + properties: EditorProperty[] = [ + ...BAR_EDITOR_PROPERTY.filter( + item => !['function-cfg', 'assist-line', 'threshold'].includes(item) + ), + 'bullet-graph-selector' + ] + propertyInner = { + 'basic-style-selector': ['radiusColumnBar', 'layout'], + 'label-selector': ['hPosition', 'fontSize', 'color', 'labelFormatter'], + 'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter', 'show'], + 'x-axis-selector': [ + ...BAR_EDITOR_PROPERTY_INNER['x-axis-selector'].filter(item => item != 'position'), + 'showLengthLimit' + ], + 'y-axis-selector': [ + ...BAR_EDITOR_PROPERTY_INNER['y-axis-selector'].filter( + item => item !== 'axisValue' && item !== 'position' + ), + 'axisLabelFormatter' + ], + 'legend-selector': ['showRange', 'orient', 'fontSize', 'color', 'hPosition', 'vPosition'] + } + + async drawChart(drawOption: G2PlotDrawOptions): Promise { + const { chart, container, action } = drawOption + if (!chart.data?.data?.length) return + const result = mergeBulletData(chart) + // 处理自定义区间 + const { bullet } = parseJson(chart.customAttr).misc + if (bullet.bar.ranges.showType === 'fixed') { + const customRange = bullet.bar.ranges.fixedRange?.map(item => item.fixedRangeValue) || [0] + result.forEach(item => (item.ranges = customRange)) + } else { + result.forEach(item => (item.ranges = item.originalRanges)) + } + // 处理自定义目标值 + if (bullet.bar.target.showType === 'fixed') { + const customTarget = bullet.bar.target.value || 0 + result.forEach(item => (item.target = customTarget)) + } else { + result.forEach(item => (item.target = item.originalTarget)) + } + const initialOptions: BulletOptions = { + appendPadding: getPadding(chart), + data: result.reverse(), + measureField: 'measures', + rangeField: 'ranges', + targetField: 'target', + xField: 'title', + meta: { + title: { + type: 'cat' + } + }, + interactions: [ + { + type: 'active-region', + cfg: { + start: [{ trigger: 'element:mousemove', action: 'active-region:show' }], + end: [{ trigger: 'element:mouseleave', action: 'active-region:hide' }] + } + } + ] + } + const options = this.setupOptions(chart, initialOptions) + let newChart = null + const { Bullet: BulletClass } = await import('@antv/g2plot/esm/plots/bullet') + newChart = new BulletClass(container, options) + newChart.on('element:click', ev => { + const pointData = ev?.data?.data + const dimensionList = options.data.find(item => item.title === pointData.title)?.dimensionList + const actionParams = { + x: ev.x, + y: ev.y, + data: { + data: { + ...pointData, + dimensionList + } + } + } + action(actionParams) + }) + configPlotTooltipEvent(chart, newChart) + configAxisLabelLengthLimit(chart, newChart, null) + return newChart + } + + protected configBasicStyle(chart: Chart, options: BulletOptions): BulletOptions { + const basicStyle = parseJson(chart.customAttr).basicStyle + const { radiusColumnBar, columnBarRightAngleRadius, layout } = basicStyle + let radiusValue = 0 + let rangeLength = 1 + if (radiusColumnBar === 'roundAngle' || radiusColumnBar === 'topRoundAngle') { + radiusValue = columnBarRightAngleRadius + rangeLength = options.data[0]?.ranges?.length + } + const barRadiusStyle = { radius: Array(2).fill(radiusValue) } + const baseRadius = [...barRadiusStyle.radius, ...barRadiusStyle.radius] + options = { + ...options, + bulletStyle: { + range: datum => { + if (!datum.rKey) return { fill: 'rgba(0, 0, 0, 0)' } + if (rangeLength === 1) { + return { + radius: + radiusColumnBar === 'topRoundAngle' ? [...barRadiusStyle.radius, 0, 0] : baseRadius + } + } + if (rangeLength > 1 && datum.rKey === 'ranges_0') { + return { + radius: radiusColumnBar === 'topRoundAngle' ? [] : [0, 0, ...barRadiusStyle.radius] + } + } + if (rangeLength > 1 && datum.rKey === 'ranges_' + (rangeLength - 1)) { + return { radius: [...barRadiusStyle.radius, 0, 0] } + } + }, + measure: datum => { + if (datum.measures) { + return { + radius: + radiusColumnBar === 'topRoundAngle' ? [...barRadiusStyle.radius, 0, 0] : baseRadius + } + } else { + return undefined + } + }, + target: datum => (datum.tKey === 'target' ? { lineWidth: 2 } : undefined) + } + } + if (layout === 'vertical') options = { ...options, layout: 'vertical' } + return options + } + + protected configMisc(chart: Chart, options: BulletOptions): BulletOptions { + const { bullet } = parseJson(chart.customAttr).misc + const isDynamic = bullet.bar.ranges.showType === 'dynamic' + // 动态背景按大小升序 + const rangeColor = isDynamic + ? bullet.bar.ranges.fill + : bullet.bar.ranges.fixedRange + ?.sort((a, b) => (a.fixedRangeValue ?? 0) - (b.fixedRangeValue ?? 0)) + .map(item => item.fill) || [] + return { + ...options, + color: { + measure: [].concat(bullet.bar.measures.fill), + range: [].concat(rangeColor), + target: [].concat(bullet.bar.target.fill) + }, + size: { + measure: bullet.bar.measures.size, + range: bullet.bar.ranges.size, + target: bullet.bar.target.size + } + } + } + + protected configXAxis(chart: Chart, options: BulletOptions): BulletOptions { + const tmpOptions = super.configXAxis(chart, options) + if (!tmpOptions.xAxis || !tmpOptions.xAxis.label) return tmpOptions + + const { layout, xAxis } = tmpOptions + const position = xAxis.position + const style: any = { ...xAxis.label.style } + + if (layout === 'vertical') { + style.textAlign = 'center' + style.textBaseline = position === 'bottom' ? 'top' : 'bottom' + } else { + style.textAlign = position === 'bottom' ? 'end' : 'start' + style.textBaseline = 'middle' + } + + xAxis.label.style = style + return tmpOptions + } + + protected configYAxis(chart: Chart, options: BulletOptions): BulletOptions { + const tmpOptions = super.configYAxis(chart, options) + if (!tmpOptions.yAxis || !tmpOptions.yAxis.label) return tmpOptions + + const yAxis = parseJson(chart.customStyle).yAxis + tmpOptions.yAxis.label.formatter = value => valueFormatter(value, yAxis.axisLabelFormatter) + + const { layout, yAxis: yAxisConfig } = tmpOptions + const position = yAxisConfig.position + const style: any = { ...yAxisConfig.label.style } + + if (layout === 'vertical') { + style.textAlign = position === 'left' ? 'end' : 'start' + style.textBaseline = 'middle' + } else { + style.textAlign = 'center' + style.textBaseline = position === 'left' ? 'top' : 'bottom' + } + + yAxisConfig.label.style = style + return tmpOptions + } + + protected configLabel(chart: Chart, options: BulletOptions): BulletOptions { + const tmpOptions = super.configLabel(chart, options) + if (!tmpOptions.label) return tmpOptions + + const labelAttr = parseJson(chart.customAttr).label + const label: any = { + ...tmpOptions.label, + formatter: param => + param.mKey === 'measures' + ? valueFormatter(param.measures, labelAttr.labelFormatter) + : undefined + } + return { ...tmpOptions, label: { measure: label } } + } + + protected configLegend(chart: Chart, options: BulletOptions): BulletOptions { + const baseLegend = super.configLegend(chart, options).legend + if (!baseLegend) return options + + const { bullet } = parseJson(chart.customAttr).misc + const customStyleLegend = parseJson(chart.customStyle).legend + const items = [] + + const createLegendItem = (value, name, symbol, fill, size = 4) => ({ + value, + name, + marker: { symbol, style: { fill, stroke: value === 'measure' ? '' : fill, r: size } } + }) + + if (customStyleLegend.showRange) { + if (bullet.bar.ranges.showType === 'dynamic') { + if (chart.extBubble.length) { + const rangeName = chart.extBubble[0]?.chartShowName || bullet.bar.ranges.name + items.push( + createLegendItem( + 'dynamic', + rangeName || chart.extBubble[0]?.name, + bullet.bar.ranges.symbol, + [].concat(bullet.bar.ranges.fill)[0], + bullet.bar.ranges.symbolSize + ) + ) + } + } else { + bullet.bar.ranges.fixedRange?.forEach(item => { + items.push( + createLegendItem( + item.name, + item.name, + bullet.bar.ranges.symbol, + item.fill, + bullet.bar.ranges.symbolSize + ) + ) + }) + } + } + + const targetName = chart.yAxisExt[0]?.chartShowName || bullet.bar.target.name + items.push( + createLegendItem( + 'target', + targetName || chart.yAxisExt[0]?.name, + 'line', + [].concat(bullet.bar.target.fill)[0], + bullet.bar.ranges.symbolSize + ) + ) + + const measureName = chart.yAxis[0]?.chartShowName || bullet.bar.measures.name + items.push( + createLegendItem( + 'measure', + measureName || chart.yAxis[0]?.name, + 'square', + [].concat(bullet.bar.measures.fill)[0], + bullet.bar.ranges.symbolSize + ) + ) + + return { + ...options, + legend: { custom: true, position: baseLegend.position, layout: baseLegend.layout, items } + } + } + + protected configTooltip(chart: Chart, options: BulletOptions): BulletOptions { + const customAttr: DeepPartial = parseJson(chart.customAttr) + const tooltipAttr = customAttr.tooltip + const { bullet } = parseJson(chart.customAttr).misc + if (!tooltipAttr.show) return { ...options, tooltip: false } + + const formatterMap = tooltipAttr.seriesTooltipFormatter + ?.filter(i => i.show) + .reduce((pre, next, index) => { + const keys = ['measures', 'target', 'ranges'] + if (keys[index]) pre[keys[index]] = next + return pre + }, {}) as Record + + const tooltip = { + shared: true, + showMarkers: true, + customItems(originalItems) { + if (!tooltipAttr.seriesTooltipFormatter?.length) return originalItems + + const result = [] + const data = options.data.find(item => item.title === originalItems[0].title) + Object.keys(formatterMap).forEach(key => { + if (key === '记录数*') return + const formatter = formatterMap[key] + if (formatter) { + if (key !== 'ranges') { + let value = 0 + if (chart.yAxis[0].id === chart.yAxisExt[0].id) { + value = valueFormatter(parseFloat(data['target'] as string), formatter.formatterCfg) + } else { + value = valueFormatter(parseFloat(data[key] as string), formatter.formatterCfg) + } + const name = isEmpty(formatter.chartShowName) + ? formatter.name + : formatter.chartShowName + result.push({ ...originalItems[0], color: bullet.bar[key].fill, name, value }) + } else { + const ranges = data.ranges + const isDynamic = bullet.bar.ranges.showType === 'dynamic' + ranges.forEach((range, index) => { + const value = valueFormatter( + parseFloat(isDynamic ? data.minRanges[0] : (range as string)), + formatter.formatterCfg + ) + let name = '' + let color: string | string[] + if (bullet.bar.ranges.showType === 'dynamic') { + name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + color = bullet.bar[key].fill + } else { + const customRange = bullet.bar.ranges.fixedRange[index].name + name = customRange + ? customRange + : isEmpty(formatter.chartShowName) + ? formatter.name + : formatter.chartShowName + color = bullet.bar[key].fixedRange[index].fill + } + result.push({ ...originalItems[0], color, name, value }) + }) + } + } + }) + const dynamicTooltipValue = chart.data.data.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 + }, + container: getTooltipContainer(`tooltip-${chart.id}`), + itemTpl: TOOLTIP_TPL, + enterable: true + } + return { ...options, tooltip } + } + + setupDefaultOptions(chart: ChartObj): ChartObj { + chart.customAttr.label.position = 'middle' + chart.customStyle.yAxis.splitLine.show = false + return super.setupDefaultOptions(chart) + } + + protected setupOptions(chart: Chart, options: BulletOptions): BulletOptions { + return flow( + this.configTheme, + this.configBasicStyle, + this.configMisc, + this.configXAxis, + this.configYAxis, + this.configLabel, + this.configLegend, + this.configTooltip + )(chart, options, {}, this) + } +} + +/** + * 组装子弹图数据 + * @param chart + */ +function mergeBulletData(chart): any[] { + // 先根据维度分组,再根据指标字段组装成子弹图的格式 + const groupedData = chart.data.data.reduce((acc, item) => { + const field = item.field + if (!acc[field]) { + acc[field] = [] + } + acc[field].push(item) + return acc + }, {}) + const result = [] + // 组装子弹图数据,每个维度对应一个子弹图 + Object.keys(groupedData).forEach(field => { + const items = groupedData[field] + // 初始化子弹图条目结构 + const entry = { + title: field, + ranges: [], + measures: [], + target: [], + dimensionList: items[0].dimensionList, + quotaList: [] + } + + // 防止指标相同时无数据有可能会导致数据不一致 + items.forEach(item => { + const quotaId = item.quotaList[0]?.id + const v = item.value || 0 + if (quotaId === chart.yAxis[0]?.id) { + entry.measures.push(v) + } + if (quotaId === chart.yAxisExt[0]?.id) { + entry.target.push(v) + } + if (quotaId === chart.extBubble[0]?.id) { + entry.ranges.push(v) + } + entry.quotaList.push(item.quotaList[0]) + }) + // 对数据进行累加 + const ranges = chart.extBubble[0]?.id + ? [].concat(entry.ranges?.reduce((acc, curr) => acc + curr, 0)) + : [] + const target = [].concat(entry.target?.reduce((acc, curr) => acc + curr, 0)) + const measures = [].concat(entry.measures?.reduce((acc, curr) => acc + curr, 0)) + const bulletData = { + ...entry, + measures: measures, + target: target, + ranges: ranges, + quotaList: [...entry.quotaList], + minRanges: ranges, + originalRanges: ranges, + originalTarget: target + } + result.push(bulletData) + }) + return result +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/bar/horizontal-bar.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/horizontal-bar.ts index 12e8ec9..a673159 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/bar/horizontal-bar.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/horizontal-bar.ts @@ -6,6 +6,7 @@ import type { Bar, BarOptions } from '@antv/g2plot/esm/plots/bar' import { configAxisLabelLengthLimit, configPlotTooltipEvent, + configRoundAngle, getPadding, getTooltipContainer, setGradientColor, @@ -101,6 +102,17 @@ export class HorizontalBar extends G2PlotChartView { const newChart = new Bar(container, options) newChart.on('interval:click', action) + if (options.label) { + newChart.on('label:click', e => { + action({ + x: e.x, + y: e.y, + data: { + data: e.target.attrs.data + } + }) + }) + } configPlotTooltipEvent(chart, newChart) configAxisLabelLengthLimit(chart, newChart) return newChart @@ -135,7 +147,10 @@ export class HorizontalBar extends G2PlotChartView { tickCount: axisValue.splitCount } } - return { ...tmpOptions, ...axis } + // 根据axis的最小值,过滤options中的data数据,过滤掉小于最小值的数据 + const { data } = options + const newData = data.filter(item => item.value >= axisValue.min) + return { ...tmpOptions, data: newData, ...axis } } return tmpOptions } @@ -157,19 +172,9 @@ export class HorizontalBar extends G2PlotChartView { color } } - if (basicStyle.radiusColumnBar === 'roundAngle') { - const barStyle = { - radius: [ - basicStyle.columnBarRightAngleRadius, - basicStyle.columnBarRightAngleRadius, - basicStyle.columnBarRightAngleRadius, - basicStyle.columnBarRightAngleRadius - ] - } - options = { - ...options, - barStyle - } + options = { + ...options, + ...configRoundAngle(chart, 'barStyle') } let barWidthRatio @@ -234,6 +239,7 @@ export class HorizontalBar extends G2PlotChartView { attrs: { x: 0, y: 0, + data, text: value, textAlign: 'start', textBaseline: 'top', @@ -316,8 +322,24 @@ export class HorizontalStackBar extends HorizontalBar { baseOptions.label.style.fill = labelAttr.color const label = { ...baseOptions.label, - formatter: function (param: Datum) { - return valueFormatter(param.value, labelAttr.labelFormatter) + formatter: function (data: Datum) { + const value = valueFormatter(data.value, labelAttr.labelFormatter) + const group = new Group({}) + group.addShape({ + type: 'text', + attrs: { + x: 0, + y: 0, + data, + text: value, + textAlign: 'start', + textBaseline: 'top', + fontSize: labelAttr.fontSize, + fontFamily: chart.fontFamily, + fill: labelAttr.color + } + }) + return group } } return { @@ -435,11 +457,29 @@ export class HorizontalPercentageStackBar extends HorizontalStackBar { const l = parseJson(customAttr).label const label = { ...baseOptions.label, - formatter: function (param: Datum) { - if (!param.value) { - return '0%' + formatter: function (data: Datum) { + let value = data.value + if (value) { + value = (Math.round(value * 10000) / 100).toFixed(l.reserveDecimalCount) + '%' + } else { + value = '0%' } - return (Math.round(param.value * 10000) / 100).toFixed(l.reserveDecimalCount) + '%' + const group = new Group({}) + group.addShape({ + type: 'text', + attrs: { + x: 0, + y: 0, + data, + text: value, + textAlign: 'start', + textBaseline: 'top', + fontSize: l.fontSize, + fontFamily: chart.fontFamily, + fill: l.color + } + }) + return group } } return { diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/bar/progress-bar.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/progress-bar.ts index b9399cf..4e0b83c 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/bar/progress-bar.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/progress-bar.ts @@ -3,8 +3,8 @@ import { flow, hexColorToRGBA, parseJson } from '../../../util' import { configAxisLabelLengthLimit, configPlotTooltipEvent, + configRoundAngle, getTooltipContainer, - getTooltipItemConditionColor, setGradientColor, TOOLTIP_TPL } from '../../common/common_antv' @@ -66,7 +66,7 @@ export class ProgressBar extends G2PlotChartView { 'fontSize', 'axisForm', 'axisLabel', - 'position', + // 'position', 'showLengthLimit' ], 'function-cfg': ['emptyDataStrategy'], @@ -166,6 +166,7 @@ export class ProgressBar extends G2PlotChartView { } }) if (basicStyle.gradient) { + // eslint-disable-next-line color1 = color1.map((ele, _index) => { return setGradientColor(ele, true, 0) }) @@ -184,19 +185,9 @@ export class ProgressBar extends G2PlotChartView { } } } - if (basicStyle.radiusColumnBar === 'roundAngle') { - const barStyle = { - radius: [ - basicStyle.columnBarRightAngleRadius, - basicStyle.columnBarRightAngleRadius, - basicStyle.columnBarRightAngleRadius, - basicStyle.columnBarRightAngleRadius - ] - } - options = { - ...options, - barStyle - } + options = { + ...options, + ...configRoundAngle(chart, 'barStyle') } let barWidthRatio @@ -297,12 +288,31 @@ export class ProgressBar extends G2PlotChartView { if (!baseOption.yAxis) { return baseOption } - if (baseOption.yAxis.position === 'left') { + baseOption.yAxis.position = 'bottom' + const yAxis = parseJson(chart.customStyle).yAxis + if (yAxis.axisLabel.show) { + const rotate = yAxis.axisLabel.rotate + let textAlign = 'end' + let textBaseline = 'middle' + if (Math.abs(rotate) > 75) { + textAlign = 'center' + } + if (rotate > 75) { + textBaseline = 'top' + } + if (rotate < -75) { + textBaseline = 'bottom' + } + baseOption.yAxis.label.style.textBaseline = textBaseline + baseOption.yAxis.label.style.textAlign = textAlign + } + + /*if (baseOption.yAxis.position === 'left') { baseOption.yAxis.position = 'bottom' } if (baseOption.yAxis.position === 'right') { baseOption.yAxis.position = 'top' - } + }*/ return baseOption } setupDefaultOptions(chart: ChartObj): ChartObj { diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/bar/range-bar.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/range-bar.ts index 5db5326..6fb82d7 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/bar/range-bar.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/range-bar.ts @@ -6,6 +6,7 @@ import type { Bar, BarOptions } from '@antv/g2plot/esm/plots/bar' import { configAxisLabelLengthLimit, configPlotTooltipEvent, + configRoundAngle, getPadding, getTooltipContainer, setGradientColor, @@ -22,6 +23,7 @@ import { import { Datum } from '@antv/g2plot/esm/types/common' import { useI18n } from '@/data-visualization/hooks/web/useI18n' import { DEFAULT_BASIC_STYLE } from '@/data-visualization/chart/components/editor/util/chart' +import { Group } from '@antv/g-canvas' const { t } = useI18n() const DEFAULT_DATA = [] @@ -170,6 +172,17 @@ export class RangeBar extends G2PlotChartView { const newChart = new BarClass(container, options) newChart.on('interval:click', action) + if (options.label) { + newChart.on('label:click', e => { + action({ + x: e.x, + y: e.y, + data: { + data: e.target.attrs.data + } + }) + }) + } configPlotTooltipEvent(chart, newChart) configAxisLabelLengthLimit(chart, newChart) return newChart @@ -309,19 +322,10 @@ export class RangeBar extends G2PlotChartView { } } } - if (basicStyle.radiusColumnBar === 'roundAngle') { - const barStyle = { - radius: [ - basicStyle.columnBarRightAngleRadius, - basicStyle.columnBarRightAngleRadius, - basicStyle.columnBarRightAngleRadius, - basicStyle.columnBarRightAngleRadius - ] - } - options = { - ...options, - barStyle - } + + options = { + ...options, + ...configRoundAngle(chart, 'barStyle') } let barWidthRatio const _v = basicStyle.columnWidthRatio ?? DEFAULT_BASIC_STYLE.columnWidthRatio @@ -391,7 +395,22 @@ export class RangeBar extends G2PlotChartView { valueFormatter(param.values[1], labelAttr.labelFormatter) } } - return res + const group = new Group({}) + group.addShape({ + type: 'text', + attrs: { + x: 0, + y: 0, + data: param, + text: res, + textAlign: 'start', + textBaseline: 'top', + fontSize: labelAttr.fontSize, + fontFamily: chart.fontFamily, + fill: labelAttr.color + } + }) + return group } } return { diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/bar/waterfall.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/waterfall.ts index f827924..518c5c5 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/bar/waterfall.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/waterfall.ts @@ -72,7 +72,8 @@ export class Waterfall extends G2PlotChartView { 'axisForm', 'axisLabel', 'axisLabelFormatter', - 'showLengthLimit' + 'showLengthLimit', + 'axisLine' ], threshold: ['lineThreshold'] } diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/line/area.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/line/area.ts index 28a3fc6..8fcba3f 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/line/area.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/line/area.ts @@ -46,7 +46,8 @@ export class Area extends G2PlotChartView { 'label-selector': ['seriesLabelVPosition', 'seriesLabelFormatter', 'showExtremum'], 'tooltip-selector': [ ...LINE_EDITOR_PROPERTY_INNER['tooltip-selector'], - 'seriesTooltipFormatter' + 'seriesTooltipFormatter', + 'carousel' ] } axis: AxisType[] = [...LINE_AXIS_TYPE] @@ -103,8 +104,8 @@ export class Area extends G2PlotChartView { async drawChart(drawOptions: G2PlotDrawOptions): Promise { const { chart, container, action } = drawOptions + chart.container = container if (!chart.data?.data?.length) { - chart.container = container clearExtremum(chart) return } @@ -147,7 +148,7 @@ export class Area extends G2PlotChartView { fields: [], ...tmpOptions.label, layout: labelAttr.fullDisplay ? [{ type: 'limit-in-plot' }] : tmpOptions.label.layout, - formatter: (data: Datum, _point) => { + formatter: (data: Datum) => { if (data.EXTREME) { return '' } @@ -305,7 +306,7 @@ export class StackArea extends Area { propertyInner = { ...this['propertyInner'], 'label-selector': ['vPosition', 'fontSize', 'color', 'labelFormatter'], - 'tooltip-selector': ['fontSize', 'color', 'tooltipFormatter', 'show'] + 'tooltip-selector': ['fontSize', 'color', 'tooltipFormatter', 'show', 'carousel'] } axisConfig = { ...this['axisConfig'], diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/line/dist/stock-line.js b/frontend/src/data-visualization/chart/components/js/panel/charts/line/dist/stock-line.js new file mode 100644 index 0000000..ab16899 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/line/dist/stock-line.js @@ -0,0 +1,673 @@ +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var __spreadArrays = (this && this.__spreadArrays) || function () { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; + for (var r = Array(s), k = 0, i = 0; i < il; i++) + for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) + r[k] = a[j]; + return r; +}; +exports.__esModule = true; +exports.StockLine = void 0; +var g2plot_1 = require("@/views/chart/components/js/panel/types/impl/g2plot"); +var util_1 = require("@/views/chart/components/js/util"); +var common_1 = require("@/views/chart/components/js/panel/charts/line/common"); +var useI18n_1 = require("@/hooks/web/useI18n"); +var formatter_1 = require("@/views/chart/components/js/formatter"); +var t = useI18n_1.useI18n().t; +var DEFAULT_DATA = []; +/** + * K线图 + */ +var StockLine = /** @class */ (function (_super) { + __extends(StockLine, _super); + function StockLine(name) { + if (name === void 0) { name = 'stock-line'; } + var _this = _super.call(this, name, DEFAULT_DATA) || this; + _this.properties = [ + 'background-overall-component', + 'border-style', + 'basic-style-selector', + 'legend-selector', + 'x-axis-selector', + 'y-axis-selector', + 'title-selector', + 'tooltip-selector', + 'function-cfg', + 'jump-set', + 'linkage' + ]; + _this.propertyInner = __assign(__assign({}, common_1.LINE_EDITOR_PROPERTY_INNER), { 'function-cfg': ['emptyDataStrategy'], 'y-axis-selector': [ + 'name', + 'color', + 'fontSize', + 'position', + 'axisLabel', + 'axisLine', + 'splitLine', + 'axisLabelFormatter' + ], 'legend-selector': ['fontSize', 'color', 'show'] }); + _this.axis = ['xAxis', 'yAxis', 'filter', 'extLabel', 'extTooltip']; + _this.axisConfig = { + xAxis: { + name: t('common.component.date') + " / " + t('chart.dimension'), + limit: 1, + type: 'd' + }, + yAxis: { + name: t('chart.k_line_yaxis_tip') + " / " + t('chart.quota'), + limit: 4, + type: 'q' + } + }; + /** + * 计算收盘价平均值 + * @param data + * @param dayCount + * @param chart + */ + _this.calculateMovingAverage = function (data, dayCount, chart) { + var _a, _b; + var xAxis = chart.xAxis; + var yAxis = chart.yAxis; + // 时间字段 + var xAxisgisbiName = xAxis[0].gisbiName; + // 收盘价字段 + var yAxisgisbiName = yAxis[1].gisbiName; + var result = []; + for (var i = 0; i < data.length; i++) { + if (i < dayCount) { + result.push((_a = {}, + _a[xAxisgisbiName] = data[i][xAxisgisbiName], + _a.value = null, + _a)); + } + else { + var sum = data + .slice(i - dayCount + 1, i + 1) + .reduce(function (sum, item) { return sum + item[yAxisgisbiName]; }, 0); + result.push((_b = {}, + _b[xAxisgisbiName] = data[i][xAxisgisbiName], + _b.value = parseFloat((sum / dayCount).toFixed(3)), + _b)); + } + } + return result; + }; + /** + * 获取数据集合中对象属性值的最大最小值 + * @param data + */ + _this.calculateMinMax = function (data) { + return data.reduce(function (acc, current) { + // 获取 current 对象的所有属性值 + var values = Object.values(current); + // 过滤出数字值 + var numericValues = values.filter(function (value) { return typeof value === 'number'; }); + // 找到 current 对象的数字属性值中的最大值和最小值 + // 如果存在数字值,则计算当前对象的最大值和最小值 + if (numericValues.length > 0) { + var currentMax = Math.max.apply(Math, numericValues); + var currentMin = Math.min.apply(Math, numericValues); + // 更新全局最大值和最小值 + acc.maxValue = Math.max(acc.maxValue, currentMax); + acc.minValue = Math.min(acc.minValue, currentMin); + } + return acc; + }, { maxValue: Number.NEGATIVE_INFINITY, minValue: Number.POSITIVE_INFINITY }); + }; + /** + * 注册图表事件 + * @param data + * @param plot + * @param averagesLineData + */ + _this.registerEvent = function (data, plot, averagesLineData) { + // 监听图例点击事件,显示隐藏 + var risingVisible = true; + plot.on('legend-item:click', function (evt) { + var value = evt.target.get('delegateObject').item.value; + if (value === 'k') { + risingVisible = !risingVisible; + plot.chart.geometries.forEach(function (geom) { + if (geom.type === 'schema') { + geom.changeVisible(risingVisible); + } + }); + } + else { + var lines = plot.chart.geometries.filter(function (item) { return item.type === 'line'; }); + var points = plot.chart.geometries.filter(function (item) { return item.type === 'point'; }); + var lineIndex = 0; + for (var _i = 0, _a = averagesLineData.keys(); _i < _a.length; _i++) { + var key = _a[_i]; + lineIndex++; + if (key === value) { + lines[lineIndex - 1].changeVisible(!lines[lineIndex - 1].visible); + points[lineIndex - 1].changeVisible(!points[lineIndex - 1].visible); + } + } + } + }); + // 监听图表渲染事件 + plot.on('afterrender', function (e) { + var _a, _b; + var first = false; + if (plot.chart.options.slider.start === 0.5 && plot.chart.options.slider.end === 1) { + first = true; + } + if ((_b = (_a = e.view) === null || _a === void 0 ? void 0 : _a.options) === null || _b === void 0 ? void 0 : _b.scales) { + var startIndex = Math.floor(0.5 * data.length); + var endIndex = Math.ceil(1 * data.length); + var filteredData = data.slice(startIndex, endIndex); + var _c = _this.calculateMinMax(first ? filteredData : e.view.filteredData), maxValue_1 = _c.maxValue, minValue_1 = _c.minValue; + var a_1 = e.view.options.scales; + Object.keys(a_1).forEach(function (item) { + if (a_1[item].max) { + a_1[item].max = maxValue_1; + } + if (a_1[item].min) { + a_1[item].min = minValue_1; + } + }); + } + }); + // 监听图例组点击事件,设置缩放 + plot.on('legend-item-group:click', function (e) { + var _a, _b; + if ((_b = (_a = e.view) === null || _a === void 0 ? void 0 : _a.options) === null || _b === void 0 ? void 0 : _b.scales) { + var _c = _this.calculateMinMax(e.view.filteredData), maxValue_2 = _c.maxValue, minValue_2 = _c.minValue; + var a_2 = e.view.options.scales; + Object.keys(a_2).forEach(function (item) { + if (a_2[item].max) { + a_2[item].max = maxValue_2; + } + if (a_2[item].min) { + a_2[item].min = minValue_2; + } + }); + } + }); + // 监听滑块事件,设置缩放 + plot.on('slider:valuechanged', function (e) { + var start = e.gEvent.currentTarget.cfg.component.cfg.start; + var end = e.gEvent.currentTarget.cfg.component.cfg.end; + plot.chart.options.slider.start = start; + plot.chart.options.slider.end = end; + var startIndex = Math.floor(start * data.length); + var endIndex = Math.ceil(end * data.length); + var filteredData = data.slice(startIndex, endIndex); + var _a = _this.calculateMinMax(filteredData), maxValue = _a.maxValue, minValue = _a.minValue; + var a = e.view.options.scales; + Object.keys(a).forEach(function (item) { + if (a[item].max) { + a[item].max = maxValue; + } + if (a[item].min) { + a[item].min = minValue; + } + }); + }); + }; + return _this; + } + StockLine.prototype.drawChart = function (drawOptions) { + var _a, _b, _c, _d, _e, _f; + return __awaiter(this, void 0, Promise, function () { + var chart, action, container, xAxis, yAxis, basicStyle, colors, alpha, data, xAxisgisbiName, averages, legendItems, averagesLineData, averageLines, index, start, end, startIndex, endIndex, filteredData, _g, maxValue, minValue, _i, _h, key, axis, dateFormat, dateSplit, option, MixClass, plot; + var _j; + var _this = this; + return __generator(this, function (_k) { + switch (_k.label) { + case 0: + chart = drawOptions.chart, action = drawOptions.action, container = drawOptions.container; + if (!((_b = (_a = chart.data) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.length)) { + return [2 /*return*/]; + } + xAxis = chart.xAxis; + yAxis = chart.yAxis; + if (yAxis.length != 4) { + return [2 /*return*/]; + } + basicStyle = util_1.parseJson(chart.customAttr).basicStyle; + colors = []; + alpha = basicStyle.alpha; + basicStyle.colors.forEach(function (ele) { + colors.push(util_1.hexColorToRGBA(ele, alpha)); + }); + data = util_1.parseJson((_c = chart.data) === null || _c === void 0 ? void 0 : _c.tableRow); + xAxisgisbiName = xAxis[0].gisbiName; + averages = [5, 10, 20, 60, 120, 180]; + legendItems = [ + { + name: '日K', + value: 'k', + marker: { + symbol: function (x, y, r) { + var width = r * 1; + var height = r; + return [ + // 矩形框 + ['M', x - width - 1 / 2, y - height / 2], + ['L', x + width + 1 / 2, y - height / 2], + ['L', x + width + 1 / 2, y + height / 2], + ['L', x - width - 1 / 2, y + height / 2], + ['Z'], + // 中线 + ['M', x, y + 10 / 2], + ['L', x, y - 10 / 2] + ]; + }, + style: { fill: 'red', stroke: 'red', lineWidth: 2 } + } + } + ]; + averagesLineData = new Map(); + averages.forEach(function (item) { + averagesLineData.set('ma' + item, _this.calculateMovingAverage(data, item, chart)); + }); + // 将均线数据设置到主数据中 + data.forEach(function (item) { + var _a; + var date = item[xAxisgisbiName]; + for (var _i = 0, averagesLineData_1 = averagesLineData; _i < averagesLineData_1.length; _i++) { + var _b = averagesLineData_1[_i], key = _b[0], value = _b[1]; + item[key] = (_a = value.find(function (m) { return m[xAxisgisbiName] === date; })) === null || _a === void 0 ? void 0 : _a.value; + } + }); + averageLines = []; + index = 0; + start = 0.5; + end = 1; + startIndex = Math.floor(start * data.length); + endIndex = Math.ceil(end * data.length); + filteredData = data.slice(startIndex, endIndex); + _g = this.calculateMinMax(filteredData), maxValue = _g.maxValue, minValue = _g.minValue; + for (_i = 0, _h = averagesLineData.keys(); _i < _h.length; _i++) { + key = _h[_i]; + index++; + averageLines.push({ + type: 'line', + top: true, + options: { + smooth: false, + xField: xAxisgisbiName, + yField: key, + color: colors[index - 1], + xAxis: null, + yAxis: { + label: false, + min: minValue, + max: maxValue, + grid: null, + line: null + }, + lineStyle: { + lineWidth: 2 + } + } + }); + legendItems.push({ + name: key.toUpperCase(), + value: key, + marker: { symbol: 'hyphen', style: { stroke: colors[index - 1], lineWidth: 2 } } + }); + } + axis = (_d = chart.xAxis) !== null && _d !== void 0 ? _d : []; + dateSplit = ((_e = axis[0]) === null || _e === void 0 ? void 0 : _e.datePattern) === 'date_split' ? '/' : '-'; + switch ((_f = axis[0]) === null || _f === void 0 ? void 0 : _f.dateStyle) { + case 'y': + dateFormat = 'YYYY'; + break; + case 'y_M': + dateFormat = 'YYYY' + dateSplit + 'MM'; + break; + case 'y_M_d': + dateFormat = 'YYYY' + dateSplit + 'MM' + dateSplit + 'DD'; + break; + // case 'H_m_s': + // dateFormat = 'HH:mm:ss' + // break + case 'y_M_d_H': + dateFormat = 'YYYY' + dateSplit + 'MM' + dateSplit + 'DD' + ' HH'; + break; + case 'y_M_d_H_m': + dateFormat = 'YYYY' + dateSplit + 'MM' + dateSplit + 'DD' + ' HH:mm'; + break; + case 'y_M_d_H_m_s': + dateFormat = 'YYYY' + dateSplit + 'MM' + dateSplit + 'DD' + ' HH:mm:ss'; + break; + default: + dateFormat = 'YYYY-MM-dd HH:mm:ss'; + } + option = this.setupOptions(chart, { + data: data, + slider: { + start: 0.5, + end: 1, + textStyle: { + fontFamily: chart.fontFamily + } + }, + plots: __spreadArrays([ + { + type: 'stock', + top: true, + options: { + meta: (_j = {}, + _j[xAxisgisbiName] = { + mask: dateFormat + }, + _j), + stockStyle: { + stroke: 'black', + lineWidth: 0.5 + }, + yAxis: { + label: {}, + position: 'left', + min: minValue, + max: maxValue + }, + xField: xAxisgisbiName, + yField: [ + yAxis[0].gisbiName, + yAxis[1].gisbiName, + yAxis[2].gisbiName, + yAxis[3].gisbiName + ], + legend: { + position: 'top', + custom: true, + items: legendItems + } + } + } + ], averageLines) + }); + return [4 /*yield*/, Promise.resolve().then(function () { return require('@antv/g2plot/esm/plots/mix'); })]; + case 1: + MixClass = (_k.sent()).Mix; + plot = new MixClass(container, option); + this.registerEvent(data, plot, averagesLineData); + plot.on('schema:click', function (evt) { + var _a; + var selectSchema = evt.data.data[xAxisgisbiName]; + var paramData = util_1.parseJson((_a = chart.data) === null || _a === void 0 ? void 0 : _a.data); + var selectData = paramData.filter(function (item) { return item.field === selectSchema; }); + var quotaList = []; + selectData.forEach(function (item) { + quotaList.push(__assign(__assign({}, item.quotaList[0]), { value: item.value })); + }); + if (selectData.length) { + var param = { + x: evt.x, + y: evt.y, + data: { + data: __assign(__assign({}, evt.data.data), { value: quotaList[0].value, name: selectSchema, dimensionList: selectData[0].dimensionList, quotaList: quotaList }) + } + }; + action(param); + } + }); + return [2 /*return*/, plot]; + } + }); + }); + }; + StockLine.prototype.configBasicStyle = function (chart, options) { + // size + var customAttr = util_1.parseJson(chart.customAttr); + var s = JSON.parse(JSON.stringify(customAttr.basicStyle)); + var smooth = s.lineSmooth; + var point = { + size: s.lineSymbolSize, + shape: s.lineSymbol + }; + var lineStyle = { + lineWidth: s.lineWidth + }; + var plots = []; + options.plots.forEach(function (item) { + if (item.type === 'stock') { + plots.push(__assign({}, item)); + } + if (item.type === 'line') { + plots.push(__assign(__assign({}, item), { options: __assign(__assign({}, item.options), { smooth: smooth, point: point, lineStyle: lineStyle }) })); + } + }); + return __assign(__assign({}, options), { plots: plots }); + }; + StockLine.prototype.configTooltip = function (chart, options) { + var tooltipAttr = util_1.parseJson(chart.customAttr).tooltip; + var newPlots = []; + var linePlotList = options.plots.filter(function (item) { return item.type === 'line'; }); + linePlotList.forEach(function (item) { + newPlots.push(item); + }); + var stockPlot = options.plots.filter(function (item) { return item.type === 'stock'; })[0]; + if (!tooltipAttr.show) { + var stockOption_1 = __assign(__assign({}, stockPlot.options), { tooltip: { + showContent: false + } }); + newPlots.push(__assign(__assign({}, stockPlot), { options: stockOption_1 })); + return __assign(__assign({}, options), { plots: newPlots }); + } + var showFiled = chart.data.fields; + var customTooltipItems = function (originalItems) { + var _a; + var formattedItems = originalItems.map(function (item) { + var fieldObj = showFiled.find(function (q) { return q.gisbiName === item.name; }); + var displayName = (fieldObj === null || fieldObj === void 0 ? void 0 : fieldObj.chartShowName) || (fieldObj === null || fieldObj === void 0 ? void 0 : fieldObj.name) || item.name; + var formattedName = displayName.startsWith('ma') ? displayName.toUpperCase() : displayName; + tooltipAttr.tooltipFormatter.decimalCount = 3; + var formattedValue = formatter_1.valueFormatter(item.value, tooltipAttr.tooltipFormatter); + return __assign(__assign({}, item), { name: formattedName, value: formattedValue, color: item.color }); + }); + var hasKLine = formattedItems.some(function (item) { return !item.name.startsWith('MA'); }); + var kLines = formattedItems.filter(function (item) { return !item.name.startsWith('MA'); }); + return hasKLine + ? __spreadArrays([ + { name: '日K', value: '', marker: true, color: (_a = kLines[0]) === null || _a === void 0 ? void 0 : _a.color } + ], kLines, formattedItems.filter(function (item) { return item.name.startsWith('MA'); })) : formattedItems; + }; + var formatTooltipItem = function (item) { + var size = item.name.startsWith('MA') || !item.value ? 10 : 5; + var markerMarginRight = item.name.startsWith('MA') || !item.value ? 5 : 9; + var markerMarginLeft = item.name.startsWith('MA') || !item.value ? 0 : 2; + return "\n
  • \n
    \n \n
    \n
    \n " + item.name + "\n " + (item.name.startsWith('MA') && item.value === '0' ? '-' : item.value) + "\n
    \n
  • \n "; + }; + var generateCustomTooltipContent = function (title, items) { + return "\n
    \n
    " + title + "
    \n
      \n " + items.map(formatTooltipItem).join('') + "\n
    \n
    \n "; + }; + var stockOption = __assign(__assign({}, stockPlot.options), { tooltip: { + showMarkers: true, + showCrosshairs: true, + showNil: true, + crosshairs: { + follow: true, + text: function (axisType, value, data) { + if (axisType === 'y') { + return { content: value ? value.toFixed(0) : value }; + } + return { content: data[0].title, position: 'end' }; + } + }, + showContent: true, + customItems: customTooltipItems, + customContent: generateCustomTooltipContent + } }); + newPlots.push(__assign(__assign({}, stockPlot), { options: stockOption })); + return __assign(__assign({}, options), { plots: newPlots }); + }; + StockLine.prototype.configXAxis = function (chart, options) { + var xAxisOptions = _super.prototype.configXAxis.call(this, chart, options); + if (!xAxisOptions) { + return options; + } + var newPlots = []; + var linePlotList = options.plots.filter(function (item) { return item.type === 'line'; }); + var stockPlot = options.plots.filter(function (item) { return item.type === 'stock'; })[0]; + var newStockPlot = __assign(__assign({}, stockPlot), { options: __assign(__assign({}, stockPlot.options), { xAxis: xAxisOptions['xAxis'] + ? __assign(__assign({}, stockPlot.options['xAxis']), xAxisOptions['xAxis']) : { + label: false, + line: null + } }) }); + newPlots.push(newStockPlot); + linePlotList.forEach(function (item) { + newPlots.push(item); + }); + return __assign(__assign({}, options), { plots: newPlots }); + }; + StockLine.prototype.configYAxis = function (chart, options) { + var yAxisOptions = _super.prototype.configYAxis.call(this, chart, options); + if (!yAxisOptions) { + return options; + } + var yAxis = util_1.parseJson(chart.customStyle).yAxis; + var newPlots = []; + var linePlotList = options.plots.filter(function (item) { return item.type === 'line'; }); + var stockPlot = options.plots.filter(function (item) { return item.type === 'stock'; })[0]; + var label = false; + if (yAxisOptions['yAxis'].label) { + label = __assign(__assign({}, yAxisOptions['yAxis'].label), { formatter: function (value) { + return formatter_1.valueFormatter(value, yAxis.axisLabelFormatter); + } }); + } + var newStockPlot = __assign(__assign({}, stockPlot), { options: __assign(__assign({}, stockPlot.options), { yAxis: label + ? __assign(__assign(__assign({}, stockPlot.options['yAxis']), yAxisOptions['yAxis']), { label: label }) : __assign(__assign({}, yAxisOptions['yAxis']), { label: label, grid: null, line: null }) }) }); + newPlots.push(newStockPlot); + linePlotList.forEach(function (item) { + newPlots.push(item); + }); + return __assign(__assign({}, options), { plots: newPlots }); + }; + StockLine.prototype.customConfigEmptyDataStrategy = function (chart, options) { + var data = options.data; + if (!(data === null || data === void 0 ? void 0 : data.length)) { + return options; + } + var strategy = util_1.parseJson(chart.senior).functionCfg.emptyDataStrategy; + if (strategy === 'ignoreData') { + var _loop_1 = function (i) { + var item = data[i]; + Object.keys(item).forEach(function (key) { + if (key.startsWith('f_') && item[key] === null) { + data.splice(i, 1); + } + }); + }; + for (var i = data.length - 1; i >= 0; i--) { + _loop_1(i); + } + } + var updateValues = function (strategy, data) { + data.forEach(function (obj) { + Object.keys(obj).forEach(function (key) { + if (key.startsWith('f_') && obj[key] === null) { + obj[key] = strategy === 'breakLine' ? null : 0; + } + }); + }); + }; + if (strategy === 'breakLine' || strategy === 'setZero') { + updateValues(strategy, data); + } + return options; + }; + StockLine.prototype.configLegend = function (chart, options) { + var legend = {}; + var customStyle; + var stockPlot = options.plots.filter(function (item) { return item.type === 'stock'; })[0]; + if (chart.customStyle) { + customStyle = util_1.parseJson(chart.customStyle); + // legend + if (customStyle.legend) { + var l = JSON.parse(JSON.stringify(customStyle.legend)); + if (l.show) { + legend = __assign(__assign({}, stockPlot.options.legend), { itemName: { + style: { + fill: l.color, + fontSize: l.fontSize + } + } }); + } + else { + legend = false; + } + } + } + var newPlots = []; + var stockOption = __assign(__assign({}, stockPlot.options), { legend: legend }); + var linePlotList = options.plots.filter(function (item) { return item.type === 'line'; }); + linePlotList.forEach(function (item) { + newPlots.push(item); + }); + newPlots.push(__assign(__assign({}, stockPlot), { options: stockOption })); + return __assign(__assign({}, options), { plots: newPlots }); + }; + StockLine.prototype.setupOptions = function (chart, options) { + return util_1.flow(this.configTheme, this.configBasicStyle, this.configXAxis, this.configYAxis, this.configTooltip, this.configLegend, this.customConfigEmptyDataStrategy)(chart, options); + }; + return StockLine; +}(g2plot_1.G2PlotChartView)); +exports.StockLine = StockLine; diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/line/line.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/line/line.ts index d128c6c..5b9b33b 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/line/line.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/line/line.ts @@ -10,10 +10,12 @@ import { TOOLTIP_TPL } from '../../common/common_antv' import { + convertToAlphaColor, flow, getLineConditions, getLineLabelColorByCondition, hexColorToRGBA, + isAlphaColor, parseJson, setUpGroupSeriesColor } from '@/data-visualization/chart/components/js/util' @@ -43,8 +45,10 @@ export class Line extends G2PlotChartView { 'label-selector': ['seriesLabelVPosition', 'seriesLabelFormatter', 'showExtremum'], 'tooltip-selector': [ ...LINE_EDITOR_PROPERTY_INNER['tooltip-selector'], - 'seriesTooltipFormatter' - ] + 'seriesTooltipFormatter', + 'carousel' + ], + 'legend-selector': [...LINE_EDITOR_PROPERTY_INNER['legend-selector'], 'legendSort'] } axis: AxisType[] = [...LINE_AXIS_TYPE, 'xAxisExt'] axisConfig = { @@ -66,8 +70,8 @@ export class Line extends G2PlotChartView { } async drawChart(drawOptions: G2PlotDrawOptions): Promise { const { chart, action, container } = drawOptions + chart.container = container if (!chart.data?.data?.length) { - chart.container = container clearExtremum(chart) return } @@ -146,7 +150,7 @@ export class Line extends G2PlotChartView { fields: [], ...tmpOptions.label, layout: labelAttr.fullDisplay ? [{ type: 'limit-in-plot' }] : tmpOptions.label.layout, - formatter: (data: Datum, _point) => { + formatter: (data: Datum) => { if (data.EXTREME) { return '' } @@ -321,17 +325,30 @@ export class Line extends G2PlotChartView { if (sort?.length) { // 用值域限定排序,有可能出现新数据但是未出现在图表上,所以这边要遍历一下子维度,加到后面,让新数据显示出来 const data = optionTmp.data - data?.forEach(d => { - const cat = d['category'] - if (cat && !sort.includes(cat)) { - sort.push(cat) + const cats = + data?.reduce((p, n) => { + const cat = n['category'] + if (cat && !p.includes(cat)) { + p.push(cat) + } + return p + }, []) || [] + const values = sort.reduce((p, n) => { + if (cats.includes(n)) { + const index = cats.indexOf(n) + if (index !== -1) { + cats.splice(index, 1) + } + p.push(n) } - }) + return p + }, []) + cats.length > 0 && values.push(...cats) optionTmp.meta = { ...optionTmp.meta, category: { type: 'cat', - values: sort + values } } } @@ -351,6 +368,56 @@ export class Line extends G2PlotChartView { fill: style.stroke } } + const { sort, customSort, icon } = customStyle.legend + if (sort && sort !== 'none' && chart.xAxisExt.length) { + const customAttr = parseJson(chart.customAttr) + const { basicStyle } = customAttr + const seriesMap = + basicStyle.seriesColor?.reduce((p, n) => { + p[n.id] = n + return p + }, {}) || {} + const dupCheck = new Set() + const items = optionTmp.data?.reduce((arr, item) => { + if (!dupCheck.has(item.category)) { + const fill = + seriesMap[item.category]?.color ?? + optionTmp.color[dupCheck.size % optionTmp.color.length] + dupCheck.add(item.category) + arr.push({ + name: item.category, + value: item.category, + marker: { + symbol: icon, + style: { + r: size, + fill: isAlphaColor(fill) ? fill : convertToAlphaColor(fill, basicStyle.alpha) + } + } + }) + } + return arr + }, []) + if (sort !== 'custom') { + items.sort((a, b) => { + return sort !== 'desc' ? a.name.localeCompare(b.name) : b.name.localeCompare(a.name) + }) + } else { + const tmp = [] + ;(customSort || []).forEach(item => { + const index = items.findIndex(i => i.name === item) + if (index !== -1) { + tmp.push(items[index]) + items.splice(index, 1) + } + }) + items.unshift(...tmp) + } + optionTmp.legend.items = items + if (xAxisExt?.customSort?.length > 0) { + delete optionTmp.meta?.category.values + } + } return optionTmp } protected setupOptions(chart: Chart, options: LineOptions): LineOptions { diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/line/stock-line.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/line/stock-line.ts index 625ad65..f621de1 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/line/stock-line.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/line/stock-line.ts @@ -68,22 +68,22 @@ export class StockLine extends G2PlotChartView { const xAxis = chart.xAxis const yAxis = chart.yAxis // 时间字段 - const xAxisDataeaseName = xAxis[0].dataeaseName + const xAxisgisbiName = xAxis[0].gisbiName // 收盘价字段 - const yAxisDataeaseName = yAxis[1].dataeaseName + const yAxisgisbiName = yAxis[1].gisbiName const result = [] for (let i = 0; i < data.length; i++) { if (i < dayCount) { result.push({ - [xAxisDataeaseName]: data[i][xAxisDataeaseName], + [xAxisgisbiName]: data[i][xAxisgisbiName], value: null }) } else { const sum = data .slice(i - dayCount + 1, i + 1) - .reduce((sum, item) => sum + item[yAxisDataeaseName], 0) + .reduce((sum, item) => sum + item[yAxisgisbiName], 0) result.push({ - [xAxisDataeaseName]: data[i][xAxisDataeaseName], + [xAxisgisbiName]: data[i][xAxisgisbiName], value: parseFloat((sum / dayCount).toFixed(3)) }) } @@ -228,7 +228,7 @@ export class StockLine extends G2PlotChartView { const data = parseJson(chart.data?.tableRow) // 时间字段 - const xAxisDataeaseName = xAxis[0].dataeaseName + const xAxisgisbiName = xAxis[0].gisbiName const averages = [5, 10, 20, 60, 120, 180] const legendItems: any[] = [ { @@ -262,9 +262,9 @@ export class StockLine extends G2PlotChartView { // 将均线数据设置到主数据中 data.forEach((item: any) => { - const date = item[xAxisDataeaseName] + const date = item[xAxisgisbiName] for (const [key, value] of averagesLineData) { - item[key] = value.find(m => m[xAxisDataeaseName] === date)?.value + item[key] = value.find(m => m[xAxisgisbiName] === date)?.value } }) @@ -283,7 +283,7 @@ export class StockLine extends G2PlotChartView { top: true, options: { smooth: false, - xField: xAxisDataeaseName, + xField: xAxisgisbiName, yField: key, color: colors[index - 1], xAxis: null, @@ -349,7 +349,7 @@ export class StockLine extends G2PlotChartView { options: { meta: { - [xAxisDataeaseName]: { + [xAxisgisbiName]: { mask: dateFormat } }, @@ -363,12 +363,12 @@ export class StockLine extends G2PlotChartView { min: minValue, max: maxValue }, - xField: xAxisDataeaseName, + xField: xAxisgisbiName, yField: [ - yAxis[0].dataeaseName, - yAxis[1].dataeaseName, - yAxis[2].dataeaseName, - yAxis[3].dataeaseName + yAxis[0].gisbiName, + yAxis[1].gisbiName, + yAxis[2].gisbiName, + yAxis[3].gisbiName ], legend: { position: 'top', @@ -384,7 +384,7 @@ export class StockLine extends G2PlotChartView { const plot = new MixClass(container, option) this.registerEvent(data, plot, averagesLineData) plot.on('schema:click', evt => { - const selectSchema = evt.data.data[xAxisDataeaseName] + const selectSchema = evt.data.data[xAxisgisbiName] const paramData = parseJson(chart.data?.data) const selectData = paramData.filter(item => item.field === selectSchema) const quotaList = [] @@ -440,7 +440,6 @@ export class StockLine extends G2PlotChartView { protected configTooltip(chart: Chart, options: MixOptions): MixOptions { const tooltipAttr = parseJson(chart.customAttr).tooltip - const xAxis = chart.xAxis const newPlots = [] const linePlotList = options.plots.filter(item => item.type === 'line') linePlotList.forEach(item => { @@ -464,7 +463,7 @@ export class StockLine extends G2PlotChartView { const showFiled = chart.data.fields const customTooltipItems = originalItems => { const formattedItems = originalItems.map(item => { - const fieldObj = showFiled.find(q => q.dataeaseName === item.name) + const fieldObj = showFiled.find(q => q.gisbiName === item.name) const displayName = fieldObj?.chartShowName || fieldObj?.name || item.name const formattedName = displayName.startsWith('ma') ? displayName.toUpperCase() : displayName tooltipAttr.tooltipFormatter.decimalCount = 3 diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/liquid/liquid.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/liquid/liquid.ts index 9ca812c..f53ed62 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/liquid/liquid.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/liquid/liquid.ts @@ -74,7 +74,7 @@ export class Liquid extends G2PlotChartView { }) // 处理空数据, 只要有一个指标是空数据,就不显示图表 const hasNoneData = chart.data?.series.some(s => !s.data?.[0]) - this.configEmptyDataStyle(newChart, hasNoneData ? [] : [1], container) + this.configEmptyDataStyle(hasNoneData ? [] : [1], container, newChart) if (hasNoneData) { return } diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/map/bubble-map.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/map/bubble-map.ts index d9554e9..039df76 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/map/bubble-map.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/map/bubble-map.ts @@ -402,7 +402,8 @@ export class BubbleMap extends L7PlotChartView { content.push(name) } if (label.showQuota) { - areaMap[name] && content.push(valueFormatter(areaMap[name], label.quotaLabelFormatter)) + ;(areaMap[name] || areaMap[name] === 0) && + content.push(valueFormatter(areaMap[name], label.quotaLabelFormatter)) } item.properties['_DE_LABEL_'] = content.join('\n\n') } diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/map/common.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/map/common.ts index 7589f4d..d9b7343 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/map/common.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/map/common.ts @@ -51,6 +51,29 @@ export const MAP_AXIS_TYPE: AxisType[] = [ 'extTooltip' ] +export const gaodeMapStyleOptions = [ + { name: t('chart.map_style_normal'), value: 'normal' }, + { name: t('chart.map_style_darkblue'), value: 'darkblue' }, + { name: t('chart.map_style_light'), value: 'light' }, + { name: t('chart.map_style_dark'), value: 'dark' }, + { name: t('chart.map_style_fresh'), value: 'fresh' }, + { name: t('chart.map_style_grey'), value: 'grey' }, + { name: t('chart.map_style_blue'), value: 'blue' }, + { name: t('chart.map_style_translate'), value: 'Satellite' }, + { name: t('commons.custom'), value: 'custom' } +] + +export const tdtMapStyleOptions = [ + { name: t('chart.map_style_normal'), value: 'normal' }, + { name: t('chart.map_style_dark'), value: 'black' }, + { name: t('chart.map_style_darkblue'), value: 'indigo' } +] + +export const qqMapStyleOptions = [ + { name: t('chart.map_style_normal'), value: 'normal' }, + { name: t('commons.custom'), value: 'custom' } +] + export declare type MapMouseEvent = MouseEvent & { feature: GeoJSON.Feature } diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/map/dist/flow-map.js b/frontend/src/data-visualization/chart/components/js/panel/charts/map/dist/flow-map.js new file mode 100644 index 0000000..1632471 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/map/dist/flow-map.js @@ -0,0 +1,391 @@ +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +exports.__esModule = true; +exports.FlowMap = void 0; +var useI18n_1 = require("@/hooks/web/useI18n"); +var l7_1 = require("@/views/chart/components/js/panel/types/impl/l7"); +var common_1 = require("@/views/chart/components/js/panel/charts/map/common"); +var util_1 = require("@/views/chart/components/js/util"); +var utils_1 = require("@/utils/utils"); +var l7_layers_1 = require("@antv/l7-layers"); +var l7_layers_2 = require("@antv/l7-layers"); +var common_antv_1 = require("@/views/chart/components/js/panel/common/common_antv"); +var t = useI18n_1.useI18n().t; +/** + * 流向地图 + */ +var FlowMap = /** @class */ (function (_super) { + __extends(FlowMap, _super); + function FlowMap() { + var _this = _super.call(this, 'flow-map', []) || this; + _this.properties = [ + 'background-overall-component', + 'border-style', + 'basic-style-selector', + 'title-selector', + 'flow-map-line-selector', + 'flow-map-point-selector', + 'bubble-animate' + ]; + _this.propertyInner = __assign(__assign({}, common_1.MAP_EDITOR_PROPERTY_INNER), { 'basic-style-selector': [ + 'mapBaseStyle', + 'mapLineStyle', + 'zoom', + 'showLabel', + 'autoFit', + 'mapCenter', + 'zoomLevel' + ] }); + _this.axis = ['xAxis', 'xAxisExt', 'filter', 'flowMapStartName', 'flowMapEndName', 'yAxis']; + _this.axisConfig = { + xAxis: { + name: t('chart.start_coordinates') + " / " + t('chart.dimension'), + type: 'd', + limit: 2 + }, + xAxisExt: { + name: t('chart.end_coordinates') + " / " + t('chart.dimension'), + type: 'd', + limit: 2 + }, + flowMapStartName: { + name: t('chart.start_name') + " / " + t('chart.dimension'), + type: 'd', + limit: 1, + allowEmpty: true + }, + flowMapEndName: { + name: t('chart.end_name') + " / " + t('chart.dimension'), + type: 'd', + limit: 1, + allowEmpty: true + }, + yAxis: { + name: t('chart.flow_map_line_width') + " / " + t('chart.quota'), + type: 'q', + limit: 1, + tooltip: t('chart.flow_map_line_width_tip'), + allowEmpty: true + } + }; + _this.lineConfig = function (chart, xAxis, xAxisExt, basicStyle, misc) { + var _a; + var flowLineStyle = { + type: misc.flowMapConfig.lineConfig.mapLineType, + size: misc.flowMapConfig.lineConfig.mapLineType === 'line' + ? misc.flowMapConfig.lineConfig.mapLineWidth / 2 + : misc.flowMapConfig.lineConfig.mapLineWidth, + animate: misc.flowMapConfig.lineConfig.mapLineAnimate, + animateDuration: misc.flowMapConfig.lineConfig.mapLineAnimateDuration, + gradient: misc.flowMapConfig.lineConfig.mapLineGradient, + sourceColor: misc.flowMapConfig.lineConfig.mapLineSourceColor, + targetColor: misc.flowMapConfig.lineConfig.mapLineTargetColor, + alpha: misc.flowMapConfig.lineConfig.alpha + }; + var colorsWithAlpha = basicStyle.colors.map(function (color) { + return util_1.hexColorToRGBA(color, misc.flowMapConfig.lineConfig.alpha); + }); + flowLineStyle.sourceColor = colorsWithAlpha[0]; + flowLineStyle.targetColor = colorsWithAlpha[1]; + // 线条粗细 + var lineWidthField = null; + var yAxis = utils_1.deepCopy(chart.yAxis); + if (yAxis.length > 0) { + lineWidthField = yAxis[0].gisbiName; + } + // 线条颜色 + var lineColorField = null; + var yAxisExt = utils_1.deepCopy(chart.yAxisExt); + if (yAxisExt.length > 0) { + lineColorField = yAxisExt[0].gisbiName; + } + var asteriskField = '*'; + var data = []; + (_a = chart.data) === null || _a === void 0 ? void 0 : _a.tableRow.forEach(function (item) { + var newKey = 'f_record'; + var newObj = Object.keys(item).reduce(function (acc, key) { + if (key === asteriskField) { + acc[newKey] = item[key]; + } + else { + acc[key] = item[key]; + } + return acc; + }, {}); + data.push(newObj); + }); + var config = new l7_layers_1.LineLayer({ + name: 'line', + blend: 'normal', + autoFit: !(basicStyle.autoFit === false) + }) + .source(data, { + parser: { + type: 'json', + x: xAxis[0].gisbiName, + y: xAxis[1].gisbiName, + x1: xAxisExt[0].gisbiName, + y1: xAxisExt[1].gisbiName + } + }) + .size(flowLineStyle.size) + .shape(flowLineStyle.type) + .animate({ + enable: flowLineStyle.animate, + duration: flowLineStyle.animateDuration, + interval: 1, + trailLength: 1 + }); + if (lineWidthField) { + config.size(lineWidthField === asteriskField ? 'f_record' : lineWidthField, [1, 10]); + } + if (lineColorField) { + config.style({ + opacity: flowLineStyle.alpha / 100 + }); + config.color(lineColorField); + } + else { + if (flowLineStyle.gradient) { + config.style({ + sourceColor: flowLineStyle.sourceColor, + targetColor: flowLineStyle.targetColor, + opacity: flowLineStyle.alpha / 100 + }); + } + else { + config + .style({ + opacity: flowLineStyle.alpha / 100 + }) + .color(flowLineStyle.sourceColor); + } + } + return config; + }; + _this.startAndEndNameConfig = function (chart, xAxis, xAxisExt, misc, configList) { + var _a, _b; + var flowMapStartName = utils_1.deepCopy(chart.flowMapStartName); + var flowMapEndName = utils_1.deepCopy(chart.flowMapEndName); + var textColor = misc.flowMapConfig.pointConfig.text.color; + var textFontSize = misc.flowMapConfig.pointConfig.text.fontSize; + var has = new Map(); + if ((flowMapStartName === null || flowMapStartName === void 0 ? void 0 : flowMapStartName.length) > 0) { + var startTextLayer = new l7_layers_2.PointLayer() + .source((_a = chart.data) === null || _a === void 0 ? void 0 : _a.tableRow, { + parser: { + type: 'json', + x: xAxis[0].gisbiName, + y: xAxis[1].gisbiName + } + }) + .shape(flowMapStartName[0].gisbiName, function (args) { + if (has.has('from-' + args)) { + return ''; + } + has.set('from-' + args, args); + return args; + }) + .size(textFontSize) + .color(textColor) + .style({ + textAnchor: 'top', + textOffset: [0, 0], + spacing: 2, + padding: [1, 1], + textAllowOverlap: true, + fontFamily: chart.fontFamily ? chart.fontFamily : undefined + }); + configList.push(startTextLayer); + } + if ((flowMapEndName === null || flowMapEndName === void 0 ? void 0 : flowMapEndName.length) > 0) { + var endTextLayer = new l7_layers_2.PointLayer() + .source((_b = chart.data) === null || _b === void 0 ? void 0 : _b.tableRow, { + parser: { + type: 'json', + x: xAxisExt[0].gisbiName, + y: xAxisExt[1].gisbiName + } + }) + .shape(flowMapEndName[0].gisbiName, function (args) { + if (has.has('from-' + args) || has.has('to-' + args)) { + return ''; + } + has.set('to-' + args, args); + return args; + }) + .size(textFontSize) + .color(textColor) + .style({ + textAnchor: 'top', + textOffset: [0, 0], + spacing: 2, + padding: [1, 1], + textAllowOverlap: true, + fontFamily: chart.fontFamily ? chart.fontFamily : undefined + }); + configList.push(endTextLayer); + } + }; + _this.pointConfig = function (chart, xAxis, xAxisExt, misc, configList) { + var _a, _b; + var color = misc.flowMapConfig.pointConfig.point.color; + var size = misc.flowMapConfig.pointConfig.point.size; + var bubbleCfg = util_1.parseJson(chart.senior).bubbleCfg; + var fromDefaultPointLayer = new l7_layers_2.PointLayer({ zIndex: -1 }) + .source((_a = chart.data) === null || _a === void 0 ? void 0 : _a.tableRow, { + parser: { + type: 'json', + x: xAxis[0].gisbiName, + y: xAxis[1].gisbiName + } + }) + .shape('circle') + .size(size) + .color(color) + .style({ + blur: 0.6 + }); + var toDefaultPointLayer = new l7_layers_2.PointLayer({ zIndex: -1 }) + .source((_b = chart.data) === null || _b === void 0 ? void 0 : _b.tableRow, { + parser: { + type: 'json', + x: xAxisExt[0].gisbiName, + y: xAxisExt[1].gisbiName + } + }) + .shape('circle') + .size(size) + .color(color) + .style({ + blur: 0.6 + }); + if (bubbleCfg && bubbleCfg.enable) { + var animate = { + enable: true, + speed: bubbleCfg.speed, + rings: bubbleCfg.rings + }; + fromDefaultPointLayer.size(size * 2); + fromDefaultPointLayer.animate(animate); + toDefaultPointLayer.size(size * 2); + toDefaultPointLayer.animate(animate); + } + configList.push(fromDefaultPointLayer); + configList.push(toDefaultPointLayer); + }; + return _this; + } + FlowMap.prototype.drawChart = function (drawOption) { + var _a; + return __awaiter(this, void 0, void 0, function () { + var chart, container, containerDom, rect, xAxis, xAxisExt, _b, basicStyle, misc, mapKey, mapStyle, chartObj, scene, center, configList, i; + return __generator(this, function (_c) { + switch (_c.label) { + case 0: + chart = drawOption.chart, container = drawOption.container; + containerDom = document.getElementById(container); + rect = containerDom === null || containerDom === void 0 ? void 0 : containerDom.getBoundingClientRect(); + if ((rect === null || rect === void 0 ? void 0 : rect.height) <= 0) { + return [2 /*return*/, new l7_1.L7Wrapper((_a = drawOption.chartObj) === null || _a === void 0 ? void 0 : _a.getScene(), [])]; + } + xAxis = utils_1.deepCopy(chart.xAxis); + xAxisExt = utils_1.deepCopy(chart.xAxisExt); + _b = utils_1.deepCopy(util_1.parseJson(chart.customAttr)), basicStyle = _b.basicStyle, misc = _b.misc; + return [4 /*yield*/, this.getMapKey()]; + case 1: + mapKey = _c.sent(); + mapStyle = common_antv_1.getMapStyle(mapKey, basicStyle); + chartObj = drawOption.chartObj; + scene = chartObj === null || chartObj === void 0 ? void 0 : chartObj.getScene(); + center = common_antv_1.getMapCenter(basicStyle); + return [4 /*yield*/, common_antv_1.getMapScene(chart, scene, container, mapKey, basicStyle, misc, mapStyle, center)]; + case 2: + scene = _c.sent(); + this.configZoomButton(chart, scene, mapKey); + if ((xAxis === null || xAxis === void 0 ? void 0 : xAxis.length) < 2 || (xAxisExt === null || xAxisExt === void 0 ? void 0 : xAxisExt.length) < 2) { + return [2 /*return*/, new l7_1.L7Wrapper(scene, undefined)]; + } + configList = []; + configList.push(this.lineConfig(chart, xAxis, xAxisExt, basicStyle, misc)); + this.startAndEndNameConfig(chart, xAxis, xAxisExt, misc, configList); + this.pointConfig(chart, xAxis, xAxisExt, misc, configList); + configList[0].once('inited', function () { + common_antv_1.mapRendered(container); + }); + for (i = 0; i < configList.length; i++) { + configList[i].on('inited', function () { + common_antv_1.qqMapRendered(scene); + }); + } + return [2 /*return*/, new l7_1.L7Wrapper(scene, configList)]; + } + }); + }); + }; + FlowMap.prototype.setupDefaultOptions = function (chart) { + chart.customAttr.misc.flowMapConfig.lineConfig.mapLineAnimate = true; + return chart; + }; + return FlowMap; +}(l7_1.L7ChartView)); +exports.FlowMap = FlowMap; diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/map/dist/symbolic-map.js b/frontend/src/data-visualization/chart/components/js/panel/charts/map/dist/symbolic-map.js new file mode 100644 index 0000000..64d59b0 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/map/dist/symbolic-map.js @@ -0,0 +1,632 @@ +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var __spreadArrays = (this && this.__spreadArrays) || function () { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; + for (var r = Array(s), k = 0, i = 0; i < il; i++) + for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) + r[k] = a[j]; + return r; +}; +exports.__esModule = true; +exports.SymbolicMap = void 0; +var useI18n_1 = require("@/hooks/web/useI18n"); +var l7_1 = require("@/views/chart/components/js/panel/types/impl/l7"); +var common_1 = require("@/views/chart/components/js/panel/charts/map/common"); +var util_1 = require("@/views/chart/components/js/util"); +var utils_1 = require("@/utils/utils"); +var l7_layers_1 = require("@antv/l7-layers"); +var l7_2 = require("@antv/l7"); +var common_antv_1 = require("@/views/chart/components/js/panel/common/common_antv"); +var tooltip_carousel_1 = require("@/views/chart/components/js/panel/charts/map/tooltip-carousel"); +var lodash_es_1 = require("lodash-es"); +var t = useI18n_1.useI18n().t; +/** + * 符号地图 + */ +var SymbolicMap = /** @class */ (function (_super) { + __extends(SymbolicMap, _super); + function SymbolicMap() { + var _this = _super.call(this, 'symbolic-map', []) || this; + _this.properties = [ + 'background-overall-component', + 'border-style', + 'basic-style-selector', + 'symbolic-style-selector', + 'title-selector', + 'label-selector', + 'tooltip-selector', + 'threshold' + ]; + _this.propertyInner = __assign(__assign({}, common_1.MAP_EDITOR_PROPERTY_INNER), { 'basic-style-selector': [ + 'colors', + 'alpha', + 'mapBaseStyle', + 'zoom', + 'showLabel', + 'autoFit', + 'mapCenter', + 'zoomLevel' + ], 'symbolic-style-selector': ['symbolicMapStyle'], 'label-selector': ['color', 'fontSize', 'showFields', 'customContent'], 'tooltip-selector': [ + 'color', + 'fontSize', + 'showFields', + 'customContent', + 'show', + 'backgroundColor', + 'carousel' + ], threshold: ['lineThreshold'] }); + _this.axis = ['xAxis', 'xAxisExt', 'extBubble', 'filter', 'extLabel', 'extTooltip']; + _this.axisConfig = { + xAxis: { + name: t('chart.symbolic_map_coordinates') + " / " + t('chart.dimension'), + type: 'd', + limit: 2 + }, + xAxisExt: { + name: t('chart.color') + " / " + t('chart.dimension'), + type: 'd', + limit: 1, + allowEmpty: true + }, + extBubble: { + name: t('chart.bubble_size') + " / " + t('chart.quota'), + type: 'q', + limit: 1, + tooltip: t('chart.symbolic_map_bubble_size_tip'), + allowEmpty: true + } + }; + /** + * 构建符号图层 + * @param chart + */ + _this.buildSymbolicLayer = function (chart, scene) { return __awaiter(_this, void 0, void 0, function () { + var basicStyle, xAxis, xAxisExt, extBubble, _a, mapSymbolOpacity, mapSymbolSize, mapSymbol, mapSymbolStrokeWidth, colors, alpha, mapSymbolSizeMin, mapSymbolSizeMax, colorsWithAlpha, colorIndex, colorAssignments, sizeKey, threshold, conditions, extBubbleIds, baseColor, baseColorList, data, pointLayer, parser, index, color, fillRegex, svgStr, doc, svgEle, parser, color, fillRegex, svgStr, doc, svgEle; + var _b, _c, _d; + return __generator(this, function (_e) { + switch (_e.label) { + case 0: + basicStyle = util_1.parseJson(chart.customAttr).basicStyle; + xAxis = utils_1.deepCopy(chart.xAxis); + xAxisExt = utils_1.deepCopy(chart.xAxisExt); + extBubble = utils_1.deepCopy(chart.extBubble); + _a = utils_1.deepCopy(basicStyle), mapSymbolOpacity = _a.mapSymbolOpacity, mapSymbolSize = _a.mapSymbolSize, mapSymbol = _a.mapSymbol, mapSymbolStrokeWidth = _a.mapSymbolStrokeWidth, colors = _a.colors, alpha = _a.alpha, mapSymbolSizeMin = _a.mapSymbolSizeMin, mapSymbolSizeMax = _a.mapSymbolSizeMax; + colorsWithAlpha = colors.map(function (color) { return util_1.hexColorToRGBA(color, alpha); }); + colorIndex = 0; + colorAssignments = new Map(); + sizeKey = extBubble.length > 0 ? extBubble[0].gisbiName : ''; + threshold = util_1.parseJson(chart.senior).threshold; + conditions = []; + if (threshold.enable) { + conditions = (_b = threshold.lineThreshold) !== null && _b !== void 0 ? _b : []; + } + extBubbleIds = chart.extBubble.map(function (i) { return i.id; }); + conditions = lodash_es_1.filter(conditions, function (c) { return extBubbleIds.includes(c.fieldId); }); + baseColor = colorsWithAlpha[0]; + baseColorList = []; + data = ((_c = chart.data) === null || _c === void 0 ? void 0 : _c.tableRow) ? chart.data.tableRow.map(function (item, index) { + var _a, _b; + item['_index'] = '_index' + index; + // 颜色标识 + var identifier = item[(_a = xAxisExt[0]) === null || _a === void 0 ? void 0 : _a.gisbiName]; + // 检查该标识是否已有颜色分配,如果没有则分配 + var color = colorAssignments.get(identifier); + if (!color) { + color = colorsWithAlpha[colorIndex++ % colorsWithAlpha.length]; + // 记录分配的颜色 + colorAssignments.set(identifier, color); + } + baseColorList[index] = color; + if (conditions.length > 0) { + for (var i = 0; i < conditions.length; i++) { + var c = conditions[i]; + var value = item[c.field.gisbiName]; + for (var _i = 0, _c = c.conditions; _i < _c.length; _i++) { + var t_1 = _c[_i]; + var v = t_1.value; + //保存一下颜色到map + var _color = util_1.getColorFormAlphaColor(t_1.color); + if (t_1.term === 'between') { + var start = parseFloat(t_1.min); + var end = parseFloat(t_1.max); + if (start <= value && value <= end) { + color = util_1.hexColorToRGBA(_color, alpha); + baseColorList[index] = color; + } + } + else if ('lt' === t_1.term) { + if (value < v) { + color = util_1.hexColorToRGBA(_color, alpha); + baseColorList[index] = color; + } + } + else if ('le' === t_1.term) { + if (value <= v) { + color = util_1.hexColorToRGBA(_color, alpha); + baseColorList[index] = color; + } + } + else if ('gt' === t_1.term) { + if (value > v) { + color = util_1.hexColorToRGBA(_color, alpha); + baseColorList[index] = color; + } + } + else if ('ge' === t_1.term) { + if (value >= v) { + color = util_1.hexColorToRGBA(_color, alpha); + baseColorList[index] = color; + } + } + else if ('eq' === t_1.term) { + if (value === v) { + color = util_1.hexColorToRGBA(_color, alpha); + baseColorList[index] = color; + } + } + else if ('not_eq' === t_1.term) { + if (value !== v) { + color = util_1.hexColorToRGBA(_color, alpha); + baseColorList[index] = color; + } + } + } + } + } + return __assign(__assign({}, item), { color: color, size: (_b = parseInt(item[sizeKey])) !== null && _b !== void 0 ? _b : mapSymbolSize, name: identifier }); + }) + : []; + pointLayer = new l7_layers_1.PointLayer({ autoFit: !(basicStyle.autoFit === false) }) + .source(data, { + parser: { + type: 'json', + x: xAxis[0].gisbiName, + y: xAxis[1].gisbiName + } + }) + .active(true); + if (!((_d = xAxisExt[0]) === null || _d === void 0 ? void 0 : _d.gisbiName)) return [3 /*break*/, 10]; + if (!(basicStyle.mapSymbol === 'custom' && basicStyle.customIcon)) return [3 /*break*/, 8]; + if (!basicStyle.customIcon.startsWith('data')) return [3 /*break*/, 2]; + scene.removeImage('customIcon'); + return [4 /*yield*/, scene.addImage('customIcon', basicStyle.customIcon)]; + case 1: + _e.sent(); + pointLayer.shape('customIcon'); + return [3 /*break*/, 7]; + case 2: + parser = new DOMParser(); + index = 0; + _e.label = 3; + case 3: + if (!(index < Math.min(baseColorList.length, colorIndex + 1))) return [3 /*break*/, 6]; + color = baseColorList[index]; + fillRegex = /(fill="[^"]*")/g; + svgStr = basicStyle.customIcon.replace(fillRegex, ''); + doc = parser.parseFromString(svgStr, 'image/svg+xml'); + svgEle = doc.documentElement; + svgEle.setAttribute('fill', color); + scene.removeImage("icon-" + color); + return [4 /*yield*/, scene.addImage("icon-" + color, util_1.svgStrToUrl(svgEle.outerHTML))]; + case 4: + _e.sent(); + _e.label = 5; + case 5: + index++; + return [3 /*break*/, 3]; + case 6: + pointLayer.shape('color', function (c) { + return "icon-" + c; + }); + _e.label = 7; + case 7: return [3 /*break*/, 9]; + case 8: + pointLayer.shape(mapSymbol).color('_index', baseColorList); + pointLayer.style({ + stroke: { + field: 'color' + }, + strokeWidth: mapSymbolStrokeWidth, + opacity: mapSymbolOpacity / 10 + }); + _e.label = 9; + case 9: return [3 /*break*/, 16]; + case 10: + if (!(basicStyle.mapSymbol === 'custom' && basicStyle.customIcon)) return [3 /*break*/, 15]; + scene.removeImage('customIcon'); + if (!basicStyle.customIcon.startsWith('data')) return [3 /*break*/, 12]; + return [4 /*yield*/, scene.addImage('customIcon', basicStyle.customIcon)]; + case 11: + _e.sent(); + pointLayer.shape('customIcon'); + return [3 /*break*/, 14]; + case 12: + parser = new DOMParser(); + color = baseColor; + fillRegex = /(fill="[^"]*")/g; + svgStr = basicStyle.customIcon.replace(fillRegex, ''); + doc = parser.parseFromString(svgStr, 'image/svg+xml'); + svgEle = doc.documentElement; + svgEle.setAttribute('fill', color); + return [4 /*yield*/, scene.addImage("customIcon", util_1.svgStrToUrl(svgEle.outerHTML))]; + case 13: + _e.sent(); + pointLayer.shape('customIcon'); + _e.label = 14; + case 14: return [3 /*break*/, 16]; + case 15: + pointLayer + .shape(mapSymbol) + .color('_index', baseColorList) + .style({ + stroke: { + field: 'color' + }, + strokeWidth: mapSymbolStrokeWidth, + opacity: mapSymbolOpacity / 10 + }); + _e.label = 16; + case 16: + if (sizeKey) { + pointLayer.size('size', [mapSymbolSizeMin, mapSymbolSizeMax]); + } + else { + pointLayer.size(mapSymbolSize); + } + return [2 /*return*/, pointLayer]; + } + }); + }); }; + /** + * 合并详情到 map + * @param details + * @returns {Map} + */ + _this.mergeDetailsToMap = function (details) { + var resultMap = new Map(); + details.forEach(function (item) { + Object.entries(item).forEach(function (_a) { + var key = _a[0], value = _a[1]; + if (resultMap.has(key)) { + var existingValue = resultMap.get(key); + if (existingValue !== value) { + resultMap.set(key, existingValue + ", " + value); + } + } + else { + resultMap.set(key, value); + } + }); + }); + return resultMap; + }; + /** + * 清除 popup + * @param container + */ + _this.clearPopup = function (container) { + var containerElement = document.getElementById(container); + containerElement === null || containerElement === void 0 ? void 0 : containerElement.querySelectorAll('.l7-popup').forEach(function (element) { return element.remove(); }); + }; + /** + * 构建 tooltip + * @param chart + * @param pointLayer + */ + _this.buildTooltip = function (chart, container, pointLayer, scene) { + var _a, _b; + var customAttr = chart.customAttr ? util_1.parseJson(chart.customAttr) : null; + _this.clearPopup(container); + if ((_a = customAttr === null || customAttr === void 0 ? void 0 : customAttr.tooltip) === null || _a === void 0 ? void 0 : _a.show) { + var tooltip_1 = utils_1.deepCopy(customAttr).tooltip; + var showFields_1 = tooltip_1.showFields || []; + if (!tooltip_1.showFields || tooltip_1.showFields.length === 0) { + showFields_1 = __spreadArrays(chart.xAxisExt.map(function (i) { return i.gisbiName + "@" + i.name; }), chart.xAxis.map(function (i) { return i.gisbiName + "@" + i.name; })); + } + // 修改背景色 + var styleId = 'tooltip-' + container; + var styleElement = document.getElementById(styleId); + if (styleElement) { + styleElement.remove(); + (_b = styleElement.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(styleElement); + } + var style = document.createElement('style'); + style.id = styleId; + style.innerHTML = "\n #" + container + " .l7-popup-content {\n background-color: " + tooltip_1.backgroundColor + " !important;\n padding: 6px 10px 6px;\n line-height: 1.6;\n border-top-left-radius: 3px;\n }\n #" + container + " .l7-popup-tip {\n border-top-color: " + tooltip_1.backgroundColor + " !important;\n }\n "; + document.head.appendChild(style); + var htmlPrefix_1 = "
    "; + var htmlSuffix_1 = '
    '; + var containerElement_1 = document.getElementById(container); + if (containerElement_1) { + containerElement_1.addEventListener('mousemove', function (event) { + var rect = containerElement_1.getBoundingClientRect(); + var mouseX = event.clientX - rect.left; + var mouseY = event.clientY - rect.top; + var tooltipElement = containerElement_1.getElementsByClassName('l7-popup'); + for (var i = 0; i < (tooltipElement === null || tooltipElement === void 0 ? void 0 : tooltipElement.length); i++) { + var element = tooltipElement[i]; + element.firstElementChild.style.display = 'none'; + element.style.transform = 'translate(15px, 12px)'; + var isNearRightEdge = containerElement_1.clientWidth - mouseX <= element.clientWidth + 10; + var isNearBottomEdge = containerElement_1.clientHeight - mouseY <= element.clientHeight; + var transform = ''; + if (isNearRightEdge) { + transform += 'translateX(-120%) translateY(15%) '; + } + if (isNearBottomEdge) { + transform += 'translateX(15%) translateY(-80%) '; + } + if (transform) { + element.style.transform = transform.trim(); + } + } + }); + } + pointLayer.on('touchend', function (e) { + var _a; + if (e.lngLat) { + var fieldData = __assign(__assign({}, e.feature), Object.fromEntries(_this.mergeDetailsToMap((_a = e.feature.details) !== null && _a !== void 0 ? _a : []))); + var content = _this.buildTooltipContent(tooltip_1, fieldData, showFields_1); + var popup = new l7_2.Popup({ + lngLat: e.lngLat, + title: '', + closeButton: false, + closeOnClick: true, + html: "" + htmlPrefix_1 + content + htmlSuffix_1 + }); + scene.addPopup(popup); + } + }); + return new l7_2.LayerPopup({ + anchor: 'top-left', + className: 'l7-popup-' + container, + items: [ + { + layer: pointLayer, + customContent: function (item) { + var fieldData = __assign(__assign({}, item), Object.fromEntries(_this.mergeDetailsToMap(item.details))); + var content = _this.buildTooltipContent(tooltip_1, fieldData, showFields_1); + return "" + htmlPrefix_1 + content + htmlSuffix_1; + } + } + ], + trigger: 'hover' + }); + } + return undefined; + }; + /** + * 构建 tooltip 内容 + * @param tooltip + * @param fieldData + * @param showFields + * @returns {string} + */ + _this.buildTooltipContent = function (tooltip, fieldData, showFields) { + var content = ""; + if (tooltip.customContent) { + content = tooltip.customContent; + showFields.forEach(function (field) { + content = content.replace("${" + field.split('@')[1] + "}", fieldData[field.split('@')[0]]); + }); + } + else { + showFields.forEach(function (field) { + content += "" + field.split('@')[1] + ": " + fieldData[field.split('@')[0]] + "
    "; + }); + } + return content.replace(/\n/g, '
    '); + }; + /** + * 构建 label + * @param chart + * @param configList + */ + _this.buildLabel = function (chart, configList) { + var _a, _b; + var xAxis = utils_1.deepCopy(chart.xAxis); + var customAttr = chart.customAttr ? util_1.parseJson(chart.customAttr) : null; + if ((_a = customAttr === null || customAttr === void 0 ? void 0 : customAttr.label) === null || _a === void 0 ? void 0 : _a.show) { + var label_1 = customAttr.label; + var data = ((_b = chart.data) === null || _b === void 0 ? void 0 : _b.tableRow) || []; + var showFields_2 = label_1.showFields || []; + if (!label_1.showFields || label_1.showFields.length === 0) { + showFields_2 = __spreadArrays(chart.xAxisExt.map(function (i) { return i.gisbiName + "@" + i.name; }), chart.xAxis.map(function (i) { return i.gisbiName + "@" + i.name; })); + } + data.forEach(function (item) { + var fieldData = __assign(__assign({}, item), Object.fromEntries(_this.mergeDetailsToMap(item.details))); + var content = label_1.customContent || ''; + if (content) { + showFields_2.forEach(function (field) { + var _a = field.split('@'), fieldKey = _a[0], fieldName = _a[1]; + content = content.replace("${" + fieldName + "}", fieldData[fieldKey]); + }); + } + else { + content = showFields_2.map(function (field) { return fieldData[field.split('@')[0]]; }).join(','); + } + content = content.replace(/\n/g, ''); + item.textLayerContent = content; + }); + configList.push(new l7_layers_1.PointLayer() + .source(data, { + parser: { + type: 'json', + x: xAxis[0].gisbiName, + y: xAxis[1].gisbiName + } + }) + .shape('textLayerContent', 'text') + .color(label_1.color) + .size(label_1.fontSize) + .style({ + textAllowOverlap: label_1.fullDisplay, + textAnchor: 'center', + textOffset: [0, 0], + fontFamily: chart.fontFamily ? chart.fontFamily : undefined + })); + } + }; + return _this; + } + SymbolicMap.prototype.drawChart = function (drawOption) { + var _a, _b, _c, _d, _e, _f, _g, _h; + return __awaiter(this, void 0, void 0, function () { + var chart, container, action, containerDom, rect, xAxis, basicStyle, miscStyle, mapKey, mapStyle, center, lng, lat, chartObj, scene, configList, symbolicLayer, tooltipLayer; + return __generator(this, function (_j) { + switch (_j.label) { + case 0: + chart = drawOption.chart, container = drawOption.container, action = drawOption.action; + containerDom = document.getElementById(container); + rect = containerDom === null || containerDom === void 0 ? void 0 : containerDom.getBoundingClientRect(); + if ((rect === null || rect === void 0 ? void 0 : rect.height) <= 0) { + return [2 /*return*/, new l7_1.L7Wrapper((_a = drawOption.chartObj) === null || _a === void 0 ? void 0 : _a.getScene(), [])]; + } + xAxis = utils_1.deepCopy(chart.xAxis); + if (chart.customAttr) { + basicStyle = util_1.parseJson(chart.customAttr).basicStyle; + miscStyle = util_1.parseJson(chart.customAttr).misc; + } + return [4 /*yield*/, this.getMapKey()]; + case 1: + mapKey = _j.sent(); + mapStyle = common_antv_1.getMapStyle(mapKey, basicStyle); + center = common_antv_1.getMapCenter(basicStyle); + // 联动时,聚焦到数据点,多个取第一个 + if (((_c = (_b = chart.chartExtRequest) === null || _b === void 0 ? void 0 : _b.linkageFilters) === null || _c === void 0 ? void 0 : _c.length) && + (xAxis === null || xAxis === void 0 ? void 0 : xAxis.length) === 2 && ((_d = chart.data) === null || _d === void 0 ? void 0 : _d.tableRow.length)) { + lng = (_f = (_e = chart.data) === null || _e === void 0 ? void 0 : _e.tableRow) === null || _f === void 0 ? void 0 : _f[0][chart.xAxis[0].gisbiName]; + lat = (_h = (_g = chart.data) === null || _g === void 0 ? void 0 : _g.tableRow) === null || _h === void 0 ? void 0 : _h[0][chart.xAxis[1].gisbiName]; + center = [lng, lat]; + } + chartObj = drawOption.chartObj; + scene = chartObj === null || chartObj === void 0 ? void 0 : chartObj.getScene(); + return [4 /*yield*/, common_antv_1.getMapScene(chart, scene, container, mapKey, basicStyle, miscStyle, mapStyle, center)]; + case 2: + scene = _j.sent(); + this.configZoomButton(chart, scene, mapKey); + if ((xAxis === null || xAxis === void 0 ? void 0 : xAxis.length) < 2) { + return [2 /*return*/, new l7_1.L7Wrapper(scene, undefined)]; + } + configList = []; + return [4 /*yield*/, this.buildSymbolicLayer(chart, scene)]; + case 3: + symbolicLayer = _j.sent(); + configList.push(symbolicLayer); + tooltipLayer = this.buildTooltip(chart, container, symbolicLayer, scene); + if (tooltipLayer) { + scene.addPopup(tooltipLayer); + } + this.buildLabel(chart, configList); + symbolicLayer.once('inited', function () { + common_antv_1.mapRendered(container); + }); + symbolicLayer.on('inited', function () { + chart.container = container; + tooltip_carousel_1.configCarouselTooltip(chart, symbolicLayer, symbolicLayer.sourceOption.data, scene); + common_antv_1.qqMapRendered(scene); + }); + symbolicLayer.on('click', function (ev) { + var data = ev.feature; + var dimensionList = []; + var quotaList = []; + chart.data.fields.forEach(function (item, index) { + Object.keys(data).forEach(function (key) { + if (key.startsWith('f_') && item.gisbiName === key) { + if (index === 0) { + dimensionList.push({ + id: item.id, + gisbiName: item.gisbiName, + value: data[key] + }); + } + else { + quotaList.push({ + id: item.id, + gisbiName: item.gisbiName, + value: data[key] + }); + } + } + }); + }); + action({ + x: ev.x, + y: ev.y, + data: { + data: __assign(__assign({}, data), { value: quotaList[0].value, name: dimensionList[0].id, dimensionList: dimensionList, quotaList: quotaList }) + } + }); + }); + return [2 /*return*/, new l7_1.L7Wrapper(scene, configList)]; + } + }); + }); + }; + SymbolicMap.prototype.setupDefaultOptions = function (chart) { + chart.customAttr.label = __assign(__assign({}, chart.customAttr.label), { show: false }); + chart.customAttr.basicStyle = __assign(__assign({}, chart.customAttr.basicStyle), { mapSymbolOpacity: 5, mapStyle: 'normal' }); + return chart; + }; + return SymbolicMap; +}(l7_1.L7ChartView)); +exports.SymbolicMap = SymbolicMap; diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/map/dist/tooltip-carousel.js b/frontend/src/data-visualization/chart/components/js/panel/charts/map/dist/tooltip-carousel.js new file mode 100644 index 0000000..ff8f4d4 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/map/dist/tooltip-carousel.js @@ -0,0 +1,558 @@ +"use strict"; +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __spreadArrays = (this && this.__spreadArrays) || function () { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; + for (var r = Array(s), k = 0, i = 0; i < il; i++) + for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) + r[k] = a[j]; + return r; +}; +exports.__esModule = true; +exports.CarouselManager = exports.carouselManagerInstances = exports.configCarouselTooltip = void 0; +var l7_1 = require("@antv/l7"); +var isEmpty_1 = require("lodash-es/isEmpty"); +var formatter_1 = require("@/views/chart/components/js/formatter"); +var util_1 = require("@/views/chart/components/js/util"); +var utils_1 = require("@/utils/utils"); +exports.configCarouselTooltip = function (chart, view, data, scene, customSubArea, drawOption) { + var _a; + if (['bubble-map', 'map'].includes(chart.type)) { + data = (_a = view.source.data.dataArray) === null || _a === void 0 ? void 0 : _a.filter(function (i) { var _a; return ((_a = i.dimensionList) === null || _a === void 0 ? void 0 : _a.length) > 0; }).reduce(function (acc, current) { + var existingItem = acc.find(function (obj) { + var _a; + if ((_a = drawOption === null || drawOption === void 0 ? void 0 : drawOption.areaId) === null || _a === void 0 ? void 0 : _a.startsWith('custom_')) { + return obj.areaName === current.areaName; + } + else { + return obj.name === current.name || (obj.adcode && obj.adcode === current.adcode); + } + }); + if (!existingItem) { + acc.push(current); + } + return acc; + }, []); + } + if (exports.carouselManagerInstances[chart.container]) { + var instances = exports.carouselManagerInstances[chart.container]; + instances.update(scene, chart, view, data, customSubArea, drawOption); + } + else { + new CarouselManager(scene, chart, view, data, customSubArea, drawOption); + } +}; +exports.carouselManagerInstances = {}; +/** + * 轮播管理类 + */ +var CarouselManager = /** @class */ (function () { + function CarouselManager(scene, chart, view, data, customSubArea, drawOption) { + var _this = this; + /** + * 停留时长定时器 + * @private + */ + this.popupTimeoutId = null; + /** + * 轮播间隔定时器 + * @private + */ + this.popupIntervalId = null; + /** + * 是否暂停轮播 + * @private + */ + this.isPaused = false; + /** + * 当前显示的数据索引 + * @private + */ + this.currentIndex = 0; + this.handleVisibilityChange = function () { + if (document.hidden) { + _this.clearPreviousInstance(_this.chart.container); + } + else { + _this.startCarouselPopups(); + } + }; + /** + * 鼠标移入暂停轮播 + */ + this.pauseCarouselPopups = function () { + var _a; + if (_this.popup) { + (_a = _this.popup) === null || _a === void 0 ? void 0 : _a.remove(); + } + _this.removeStyle(); + _this.isPaused = true; + _this.clearExistingTimers(); + }; + /** + * 鼠标移出开始轮播 + */ + this.resumeCarouselPopups = function () { + if (_this.isPaused) { + _this.isPaused = false; + _this.startCarouselPopups(); + } + }; + /** + * 清除定时器 + * @private + */ + this.clearExistingTimers = function () { + if (_this.popupTimeoutId !== null) { + clearTimeout(_this.popupTimeoutId); + _this.popupTimeoutId = 0; + } + if (_this.popupIntervalId !== null) { + clearInterval(_this.popupIntervalId); + _this.popupIntervalId = 0; + } + }; + // 绑定事件处理函数 + this.onMouseEnterHandler = this.pauseCarouselPopups.bind(this); + this.onMouseLeaveHandler = this.resumeCarouselPopups.bind(this); + this.onVisibilityChangeHandler = this.handleVisibilityChange.bind(this); + this.clearExistingTimers = this.clearExistingTimers.bind(this); + this.init(scene, chart, view, data, customSubArea, drawOption); + } + /** + * 更新轮播弹窗对象内容 + * @param scene + * @param chart + * @param view + * @param data + * @param customSubArea + */ + CarouselManager.prototype.update = function (scene, chart, view, data, customSubArea, drawOption) { + this.init(scene, chart, view, data, customSubArea, drawOption); + }; + /** + * 初始化轮播弹窗 + * @param scene + * @param chart + * @param view + * @param data + * @private + */ + CarouselManager.prototype.init = function (scene, chart, view, data, customSubArea, drawOption) { + var _this = this; + var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; + this.view = view; + this.chart = chart; + this.scene = scene; + this.data = data; + this.popup = null; + this.currentIndex = 0; + this.customSubArea = customSubArea; + this.drawOption = drawOption; + this.clearPreviousInstance(this.chart.container); + if (((_b = (_a = this.chart.customAttr) === null || _a === void 0 ? void 0 : _a.tooltip) === null || _b === void 0 ? void 0 : _b.show) && ((_e = (_d = (_c = this.chart.customAttr) === null || _c === void 0 ? void 0 : _c.tooltip) === null || _d === void 0 ? void 0 : _d.carousel) === null || _e === void 0 ? void 0 : _e.enable) && + this.data.length > 0) { + this.popup = new l7_1.Popup({ closeButton: false, maxWidth: 600 }); + var carousel = (_g = (_f = this.chart.customAttr) === null || _f === void 0 ? void 0 : _f.tooltip) === null || _g === void 0 ? void 0 : _g.carousel; + this.stayTime = carousel.stayTime * 1000; + this.intervalTime = carousel.intervalTime * 1000; + this.startCarouselPopups(); + var divElement = document.getElementById(this.chart.container); + divElement.addEventListener('mouseenter', this.pauseCarouselPopups); + divElement.addEventListener('mouseleave', this.resumeCarouselPopups); + // 移动端符号地图不支持mouseenter和mouseleave事件,这里特殊处理一下 + if (this.chart.type === 'symbolic-map') { + // 监听符号触摸事件, 暂停轮播 + (_j = (_h = scene === null || scene === void 0 ? void 0 : scene.getLayers()) === null || _h === void 0 ? void 0 : _h[0]) === null || _j === void 0 ? void 0 : _j.addListener('touchend', function () { + _this.pauseCarouselPopups(); + }); + // 地图空白区域触摸事件, 启动轮播 + (_k = scene === null || scene === void 0 ? void 0 : scene.getMapCanvasContainer()) === null || _k === void 0 ? void 0 : _k.addEventListener('touchend', function () { + _this.resumeCarouselPopups(); + }); + } + // 监听页面可见性变化 + document.addEventListener('visibilitychange', this.handleVisibilityChange); + exports.carouselManagerInstances[this.chart.container] = this; + } + }; + /** + * 清除之前的实例数据 + * @param containerId + * @private + */ + CarouselManager.prototype.clearPreviousInstance = function (containerId) { + var _a; + if (exports.carouselManagerInstances[containerId]) { + var instance = exports.carouselManagerInstances[containerId]; + this.clearExistingTimers(); + (_a = instance.popup) === null || _a === void 0 ? void 0 : _a.remove(); + instance.removeStyle(); + } + }; + /** + * 开始轮播 + * @private + */ + CarouselManager.prototype.startCarouselPopups = function () { + this.clearExistingTimers(); + this.carouselPopups(); + }; + /** + * 管理轮播弹窗的显示 + * + * 此方法用于处理轮播弹窗的显示逻辑它会根据当前的索引显示对应的弹窗, + * 并在一定时间后自动移除当前弹窗并显示下一个弹窗 + * + * @private + */ + CarouselManager.prototype.carouselPopups = function () { + var _this = this; + var showPopup = function (index) { + _this.removeStyle(); + var containerElement = document.getElementById(_this.chart.container); + if (containerElement) { + if (_this.chart.type === 'symbolic-map') { + // 轮播进行时,隐藏隐藏鼠标悬浮的tooltip + var mouseTooltip = containerElement.getElementsByClassName('l7-popup-' + _this.chart.container); + for (var _i = 0, _a = Array.from(mouseTooltip); _i < _a.length; _i++) { + var tooltip = _a[_i]; + var tooltipElement = tooltip; + tooltipElement.classList.add('l7-popup-hide'); + } + _this.createSymbolicMapPopup(index); + } + else { + if (_this.chart.type === 'map') { + // 轮播进行时,隐藏隐藏鼠标悬浮的tooltip + var mouseTooltip = containerElement.getElementsByClassName('l7plot-tooltip-container'); + for (var _b = 0, _c = Array.from(mouseTooltip); _b < _c.length; _b++) { + var tooltip = _c[_b]; + var tooltipElement = tooltip; + tooltipElement.style.display = 'none'; + } + } + _this.createPopup(index); + } + _this.clearExistingTimers(); + _this.popupTimeoutId = window.setTimeout(function () { + var _a; + _this.currentIndex++; + (_a = _this.popup) === null || _a === void 0 ? void 0 : _a.remove(); + _this.cancelHighlightLayer(index); + if (_this.currentIndex >= _this.data.length) { + _this.currentIndex = 0; + } + _this.popupIntervalId = window.setTimeout(function () { + showPopup(_this.currentIndex); + }, _this.intervalTime); + }, _this.stayTime); + } + else { + _this.clearExistingTimers(); + } + }; + showPopup(this.currentIndex); + }; + /** + * 移除样式 + * 每次创建弹窗前移除之前的样式 + * @private + */ + CarouselManager.prototype.removeStyle = function () { + var _a; + var styleToRemove = document.getElementById('style-' + this.chart.container); + if (styleToRemove) { + styleToRemove.remove(); + (_a = styleToRemove.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(styleToRemove); + } + }; + /** + * 创建弹窗信息 + * @param index + * @private + */ + CarouselManager.prototype.createPopup = function (index) { + var _this = this; + var _a, _b, _c, _d, _e, _f; + var tooltipStyle = this.view.tooltip.options.domStyles; + var tooltipBackgroundColor = tooltipStyle['l7plot-tooltip']['background-color']; + var tooltipFontSize = tooltipStyle['l7plot-tooltip']['font-size']; + var style = document.createElement('style'); + style.id = 'style-' + this.chart.container; + style.innerHTML = "\n #" + this.chart.container + " .l7-popup-content {\n background-color: " + tooltipBackgroundColor + " !important;\n font-size: " + tooltipFontSize + ";\n padding: 10px 10px 6px;\n line-height: 1.6;\n }\n #" + this.chart.container + " .l7-popup-tip {\n border-top-color: " + tooltipBackgroundColor + " !important;\n }\n "; + document.head.appendChild(style); + var popupData = this.getPopupData(index); + if (popupData.data) { + var tooltipItem_1 = ''; + this.getTooltipItems(popupData.data).forEach(function (fieldData) { + tooltipItem_1 += "\n
  • \n " + fieldData.name + "\n " + fieldData.value + "\n
  • "; + }); + var html = "\n
    \n
    " + popupData.data.name + "
    \n
      \n " + tooltipItem_1 + "\n
    \n
    \n "; + this.popup.setLngLat({ lng: popupData.centroid[0], lat: popupData.centroid[1] }); + this.popup.setHTML(html); + this.popup.closeButton = false; + this.view.addLayer(this.popup); + // 地图层高亮 + (_b = (_a = this.view.scene + .getLayers()) === null || _a === void 0 ? void 0 : _a.find(function (i) { return i.name === 'highlightLayer'; })) === null || _b === void 0 ? void 0 : _b.setData(this.getActiveData(index)); + if (this.chart.type === 'bubble-map') { + // 气泡地图高亮 + var _id = ((_d = (_c = this.view.scene + .getLayers()) === null || _c === void 0 ? void 0 : _c.find(function (i) { return i.name === 'bubbleLayer'; })) === null || _d === void 0 ? void 0 : _d.layerSource.data.dataArray.find(function (i) { return i.name === _this.data[index].name; }))._id; + (_f = (_e = this.view.scene + .getLayers()) === null || _e === void 0 ? void 0 : _e.find(function (i) { return i.name === 'bubbleLayer' && i.coordCenter; })) === null || _f === void 0 ? void 0 : _f.setActive(_id, { color: 'rgba(30,90,255,1)' }); + } + } + }; + CarouselManager.prototype.getActiveData = function (index) { + var _this = this; + var _a, _b, _c; + if ((_b = (_a = this.drawOption) === null || _a === void 0 ? void 0 : _a.areaId) === null || _b === void 0 ? void 0 : _b.startsWith('custom_')) { + var result_1 = { + type: 'FeatureCollection', + features: [] + }; + var area = this.customSubArea.find(function (a) { return a.name === _this.data[index].areaName; }); + var areaMap_1 = this.view.currentDistrictData.features.reduce(function (p, n) { + p['156' + n.properties.adcode] = n; + return p; + }, {}); + (_c = area === null || area === void 0 ? void 0 : area.scopeArr) === null || _c === void 0 ? void 0 : _c.forEach(function (s) { + if (areaMap_1[s]) { + result_1.features.push(areaMap_1[s]); + } + }); + return result_1; + } + return { + type: 'FeatureCollection', + features: [ + this.view.currentDistrictData.features.find(function (i) { return i.properties.name === _this.data[index].name; }) + ] + }; + }; + /** + * 获取弹窗信息,包括原始数据及位置信息 + * @param index + * @private + */ + CarouselManager.prototype.getPopupData = function (index) { + var _this = this; + var _a, _b, _c, _d; + if ((_b = (_a = this.drawOption) === null || _a === void 0 ? void 0 : _a.areaId) === null || _b === void 0 ? void 0 : _b.startsWith('custom_')) { + var data_1 = this.data[index]; + var area = (_c = this.customSubArea) === null || _c === void 0 ? void 0 : _c.find(function (a) { return a.name === data_1.areaName; }); + data_1.name = data_1.areaName; + return { + data: data_1, + centroid: area.centroid + }; + } + else { + return { + data: this.data[index], + centroid: (_d = this.view.currentDistrictData.features.find(function (i) { return i.properties.name === _this.data[index].name; })) === null || _d === void 0 ? void 0 : _d.properties.centroid + }; + } + }; + /** + * 将对象转换为 CSS 属性 + * @param obj + * @private + */ + CarouselManager.prototype.objectToSemicolonSeparated = function (obj) { + var result = ''; + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + result += this.convertToSnakeCase(key) + ":" + obj[key] + ";"; + } + } + return result; + }; + CarouselManager.prototype.cancelHighlightLayer = function (index) { + var _this = this; + var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o; + (_c = (_b = (_a = this.view.scene) === null || _a === void 0 ? void 0 : _a.getLayers()) === null || _b === void 0 ? void 0 : _b.find(function (i) { return i.name === 'highlightLayer'; })) === null || _c === void 0 ? void 0 : _c.setData({ type: 'FeatureCollection', features: [] }); + if (this.chart.type === 'bubble-map') { + var _id = ((_f = (_e = (_d = this.view.scene) === null || _d === void 0 ? void 0 : _d.getLayers()) === null || _e === void 0 ? void 0 : _e.find(function (i) { return i.name === 'bubbleLayer'; })) === null || _f === void 0 ? void 0 : _f.layerSource.data.dataArray.find(function (i) { return i.name === _this.data[index].name; }))._id; + (_h = (_g = this.view.scene + .getLayers()) === null || _g === void 0 ? void 0 : _g.find(function (i) { return i.name === 'bubbleLayer' && i.coordCenter; })) === null || _h === void 0 ? void 0 : _h.setActive(_id, { + color: this.view.scene + .getLayers() + .find(function (i) { return i.name === 'bubbleLayer'; }) + .styleAttributeService.getLayerStyleAttribute('color').scale.field + }); + } + if (this.chart.type === 'symbolic-map') { + var lngField_1 = this.chart.xAxis[0].gisbiName; + var latField_1 = this.chart.xAxis[1].gisbiName; + var _id = ((_l = (_k = (_j = this.scene) === null || _j === void 0 ? void 0 : _j.getLayers()) === null || _k === void 0 ? void 0 : _k.find(function (i) { return i.type === 'PointLayer'; })) === null || _l === void 0 ? void 0 : _l.layerSource.data.dataArray.find(function (i) { + var targetLng = _this.data[index][lngField_1]; + var targetLat = _this.data[index][latField_1]; + return i[lngField_1] === targetLng && i[latField_1] === targetLat; + }))._id; + (_o = (_m = this.scene + .getLayers()) === null || _m === void 0 ? void 0 : _m.find(function (i) { return i.type === 'PointLayer' && i.coordCenter; })) === null || _o === void 0 ? void 0 : _o.setActive(_id, { + color: this.scene + .getLayers() + .find(function (i) { return i.type === 'PointLayer'; }) + .styleAttributeService.getLayerStyleAttribute('color').scale.field + }); + } + }; + /** + * 将驼峰式命名转换为蛇形命名 + * @param str + * @private + */ + CarouselManager.prototype.convertToSnakeCase = function (str) { + return str.replace(/([A-Z])/g, function (match) { return '-' + match.toLowerCase(); }); + }; + /** + * 获取弹窗字段信息 + * 与tooltip要显示的内容一致 + * @param data + * @private + */ + CarouselManager.prototype.getTooltipItems = function (data) { + var _a, _b, _c, _d; + var result = []; + var customAttr = util_1.parseJson(this.chart.customAttr); + var tooltip = customAttr.tooltip; + var formatterMap = (_a = tooltip.seriesTooltipFormatter) === null || _a === void 0 ? void 0 : _a.filter(function (i) { return i.show; }).reduce(function (pre, next) { + pre[next.id] = next; + return pre; + }, {}); + if (isEmpty_1["default"](formatterMap)) { + return result; + } + var head = data; + var formatter = formatterMap[(_c = (_b = head.quotaList) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.id]; + if (!isEmpty_1["default"](formatter)) { + var originValue = parseFloat(head.value); + var value = formatter_1.valueFormatter(originValue, formatter.formatterCfg); + var name = isEmpty_1["default"](formatter.chartShowName) ? formatter.name : formatter.chartShowName; + result.push(__assign(__assign({}, head), { name: name, value: "" + (value !== null && value !== void 0 ? value : '') })); + } + (_d = head.dynamicTooltipValue) === null || _d === void 0 ? void 0 : _d.forEach(function (item) { + var formatter = formatterMap[item.fieldId]; + if (formatter) { + var value = formatter_1.valueFormatter(parseFloat(item.value), formatter.formatterCfg); + var name = isEmpty_1["default"](formatter.chartShowName) ? formatter.name : formatter.chartShowName; + result.push({ color: 'grey', name: name, value: "" + (value !== null && value !== void 0 ? value : '') }); + } + }); + return result; + }; + /** + * 符号地图特殊处理,tooltip的配置可自定义显示内容 + * @param index + * @private + */ + CarouselManager.prototype.createSymbolicMapPopup = function (index) { + var _this = this; + var buildTooltip = function () { + var _a, _b, _c, _d, _e, _f; + var customAttr = _this.chart.customAttr ? util_1.parseJson(_this.chart.customAttr) : null; + if ((_a = customAttr === null || customAttr === void 0 ? void 0 : customAttr.tooltip) === null || _a === void 0 ? void 0 : _a.show) { + if (!_this.popup) { + return undefined; + } + var tooltip = utils_1.deepCopy(customAttr).tooltip; + var showFields = tooltip.showFields || []; + if (!tooltip.showFields || tooltip.showFields.length === 0) { + showFields = __spreadArrays(_this.chart.xAxisExt.map(function (i) { return i.gisbiName + "@" + i.name; }), _this.chart.xAxis.map(function (i) { return i.gisbiName + "@" + i.name; })); + } + var style = document.createElement('style'); + style.id = 'style-' + _this.chart.container; + style.innerHTML = "\n #" + _this.chart.container + " .l7-popup-content {\n background-color: " + tooltip.backgroundColor + " !important;\n padding: 6px 10px 6px;\n line-height: 1.6;\n }\n #" + _this.chart.container + " .l7-popup-tip {\n border-top-color: " + tooltip.backgroundColor + " !important;\n }\n "; + document.head.appendChild(style); + var lngField_2 = _this.chart.xAxis[0].gisbiName; + var latField_2 = _this.chart.xAxis[1].gisbiName; + var htmlPrefix = "
    "; + var htmlSuffix = '
    '; + var data = _this.view.sourceOption.data[index]; + if (data && ((_b = data.details) === null || _b === void 0 ? void 0 : _b.length)) { + var fieldData = __assign(__assign({}, data), Object.fromEntries(mergeDetailsToMap(data.details))); + var content = buildTooltipContent(tooltip, fieldData, showFields); + var html = "" + htmlPrefix + content + htmlSuffix; + _this.popup.setLngLat({ + lng: data[lngField_2], + lat: data[latField_2] + }); + _this.popup.setHTML(html); + _this.popup.closeButton = false; + _this.scene.addPopup(_this.popup); + _this.popup.addTo(_this.scene); + var _id = ((_d = (_c = _this.scene + .getLayers()) === null || _c === void 0 ? void 0 : _c.find(function (i) { return i.type === 'PointLayer'; })) === null || _d === void 0 ? void 0 : _d.layerSource.data.dataArray.find(function (i) { + var targetLng = _this.data[index][lngField_2]; + var targetLat = _this.data[index][latField_2]; + return i[lngField_2] === targetLng && i[latField_2] === targetLat; + }))._id; + (_f = (_e = _this.scene + .getLayers()) === null || _e === void 0 ? void 0 : _e.find(function (i) { return i.type === 'PointLayer' && i.coordCenter; })) === null || _f === void 0 ? void 0 : _f.setActive(_id, { color: 'rgba(30,90,255,1)' }); + } + } + return undefined; + }; + /** + * 构建 tooltip 内容 + * @param tooltip + * @param fieldData + * @param showFields + * @returns {string} + */ + var buildTooltipContent = function (tooltip, fieldData, showFields) { + var content = ''; + if (tooltip.customContent) { + content = tooltip.customContent; + showFields.forEach(function (field) { + content = content.replace("${" + field.split('@')[1] + "}", fieldData[field.split('@')[0]]); + }); + } + else { + showFields.forEach(function (field) { + content += "" + field.split('@')[1] + ": " + fieldData[field.split('@')[0]] + "
    "; + }); + } + return content.replace(/\n/g, '
    '); + }; + /** + * 合并详情到 map + * @param details + * @returns {Map} + */ + var mergeDetailsToMap = function (details) { + var resultMap = new Map(); + details.forEach(function (item) { + Object.entries(item).forEach(function (_a) { + var key = _a[0], value = _a[1]; + if (resultMap.has(key)) { + var existingValue = resultMap.get(key); + if (existingValue !== value) { + resultMap.set(key, existingValue + ", " + value); + } + } + else { + resultMap.set(key, value); + } + }); + }); + return resultMap; + }; + buildTooltip(); + }; + return CarouselManager; +}()); +exports.CarouselManager = CarouselManager; diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/map/heat-map.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/map/heat-map.ts index 3701bbd..088db46 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/map/heat-map.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/map/heat-map.ts @@ -1,18 +1,18 @@ -import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { useI18n } from '@/hooks/web/useI18n' import { L7ChartView, L7Config, L7DrawConfig, L7Wrapper -} from '@/data-visualization/chart/components/js/panel/types/impl/l7' -import { MAP_EDITOR_PROPERTY_INNER } from '@/data-visualization/chart/components/js/panel/charts/map/common' -import { flow, parseJson } from '@/data-visualization/chart/components/js/util' -import { deepCopy } from '@/data-visualization/utils/utils' +} from '@/views/chart/components/js/panel/types/impl/l7' +import { MAP_EDITOR_PROPERTY_INNER } from '@/views/chart/components/js/panel/charts/map/common' +import { flow, parseJson } from '@/views/chart/components/js/util' +import { deepCopy } from '@/utils/utils' import { GaodeMap } from '@antv/l7-maps' import { Scene } from '@antv/l7-scene' import { HeatmapLayer } from '@antv/l7-layers' -import { DEFAULT_BASIC_STYLE } from '@/data-visualization/chart/components/editor/util/chart' -import { mapRendered, mapRendering } from '@/data-visualization/chart/components/js/panel/common/common_antv' +import { DEFAULT_BASIC_STYLE } from '@/views/chart/components/editor/util/chart' +import { mapRendered, mapRendering } from '@/views/chart/components/js/panel/common/common_antv' const { t } = useI18n() /** diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/map/map.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/map/map.ts index 51ceea3..cd18f05 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/map/map.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/map/map.ts @@ -157,6 +157,11 @@ export class Map extends L7PlotChartView { }) }) data = filterChartDataByRange(sourceData, maxValue, minValue) + if (chart.drill) { + getMaxAndMinValueByData(sourceData, 'value', 0, 0, (max, min) => { + data = filterChartDataByRange(sourceData, max, min) + }) + } } else { data = sourceData } @@ -301,7 +306,8 @@ export class Map extends L7PlotChartView { content.push(name) } if (label.showQuota) { - areaMap[name] && content.push(valueFormatter(areaMap[name], label.quotaLabelFormatter)) + ;(areaMap[name] || areaMap[name] === 0) && + content.push(valueFormatter(areaMap[name], label.quotaLabelFormatter)) } item.properties['_DE_LABEL_'] = content.join('\n\n') } @@ -346,11 +352,7 @@ export class Map extends L7PlotChartView { return listDom } - private customConfigLegend( - chart: Chart, - options: ChoroplethOptions, - context: Record - ): ChoroplethOptions { + private customConfigLegend(chart: Chart, options: ChoroplethOptions): ChoroplethOptions { const { basicStyle, misc } = parseJson(chart.customAttr) const colors = basicStyle.colors.map(item => hexColorToRGBA(item, basicStyle.alpha)) if (basicStyle.suspension === false && basicStyle.showZoom === undefined) { @@ -420,14 +422,14 @@ export class Map extends L7PlotChartView { const isLessThanMin = range[0] < ranges[0][0] && range[1] < ranges[0][0] let rangeColor = colors[colorIndex] if (isLessThanMin) { - rangeColor = hexColorToRGBA(basicStyle.areaBaseColor, basicStyle.alpha) + rangeColor = basicStyle.areaBaseColor } items.push({ value: tmpRange, color: rangeColor }) }) - customLegend['customContent'] = (_: string, _items: CategoryLegendListItem[]) => { + customLegend['customContent'] = () => { if (items?.length) { return this.createLegendCustomContent(items) } @@ -435,13 +437,16 @@ export class Map extends L7PlotChartView { } options.color['value'] = ({ value }) => { const item = items.find(item => value >= item.value[0] && value <= item.value[1]) - return item ? item.color : hexColorToRGBA(basicStyle.areaBaseColor, basicStyle.alpha) + return item ? item.color : basicStyle.areaBaseColor } options.color.scale.domain = [ranges[0][0], ranges[ranges.length - 1][1]] } else { customLegend['customContent'] = (_: string, items: CategoryLegendListItem[]) => { const showItems = items?.length > 30 ? items.slice(0, 30) : items if (showItems?.length) { + if (showItems.length === 1) { + showItems[0].value = options.color.scale.domain.slice(0, 2) + } return this.createLegendCustomContent(showItems) } return '' @@ -508,7 +513,7 @@ export class Map extends L7PlotChartView { content.push(area.name) } if (label.showQuota) { - areaMap[area.name] && + ;(areaMap[area.name] || areaMap[area.name] === 0) && content.push(valueFormatter(areaMap[area.name].value, label.quotaLabelFormatter)) } labelLocation.push({ @@ -567,6 +572,9 @@ export class Map extends L7PlotChartView { return result } const head = originalItem.properties + if (!head) { + return result + } const { adcode } = head const areaName = subAreaMap['156' + adcode] const valItem = areaMap[areaName] diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/map/symbolic-map.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/map/symbolic-map.ts index 8e16a7a..61c5502 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/map/symbolic-map.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/map/symbolic-map.ts @@ -1,4 +1,4 @@ -import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { useI18n } from '@/hooks/web/useI18n' import { L7ChartView, L7Config, @@ -13,13 +13,17 @@ import { svgStrToUrl } from '@/data-visualization/chart/components/js/util' import { deepCopy } from '@/data-visualization/utils/utils' -import { GaodeMap } from '@antv/l7-maps' import { Scene } from '@antv/l7-scene' import { PointLayer } from '@antv/l7-layers' import { LayerPopup, Popup } from '@antv/l7' -import { mapRendered, mapRendering } from '@/data-visualization/chart/components/js/panel/common/common_antv' +import { + getMapCenter, + getMapScene, + getMapStyle, + mapRendered, + qqMapRendered +} from '@/data-visualization/chart/components/js/panel/common/common_antv' import { configCarouselTooltip } from '@/data-visualization/chart/components/js/panel/charts/map/tooltip-carousel' -import { DEFAULT_BASIC_STYLE } from '@/data-visualization/chart/components/editor/util/chart' import { filter } from 'lodash-es' const { t } = useI18n() @@ -102,18 +106,10 @@ export class SymbolicMap extends L7ChartView { miscStyle = parseJson(chart.customAttr).misc } - let mapStyle = basicStyle.mapStyleUrl - if (basicStyle.mapStyle !== 'custom') { - mapStyle = `amap://styles/${basicStyle.mapStyle ? basicStyle.mapStyle : 'normal'}` - } const mapKey = await this.getMapKey() - let center: [number, number] = [ - DEFAULT_BASIC_STYLE.mapCenter.longitude, - DEFAULT_BASIC_STYLE.mapCenter.latitude - ] - if (basicStyle.autoFit === false) { - center = [basicStyle.mapCenter.longitude, basicStyle.mapCenter.latitude] - } + const mapStyle = getMapStyle(mapKey, basicStyle) + + let center = getMapCenter(basicStyle) // 联动时,聚焦到数据点,多个取第一个 if ( chart.chartExtRequest?.linkageFilters?.length && @@ -121,45 +117,25 @@ export class SymbolicMap extends L7ChartView { chart.data?.tableRow.length ) { // 经度 - const lng = chart.data?.tableRow?.[0][chart.xAxis[0].dataeaseName] + const lng = chart.data?.tableRow?.[0][chart.xAxis[0].gisbiName] // 纬度 - const lat = chart.data?.tableRow?.[0][chart.xAxis[1].dataeaseName] + const lat = chart.data?.tableRow?.[0][chart.xAxis[1].gisbiName] center = [lng, lat] } const chartObj = drawOption.chartObj as unknown as L7Wrapper let scene = chartObj?.getScene() - if (!scene) { - scene = new Scene({ - id: container, - logoVisible: false, - map: new GaodeMap({ - token: mapKey?.key ?? undefined, - style: mapStyle, - pitch: miscStyle.mapPitch, - center, - zoom: basicStyle.autoFit === false ? basicStyle.zoomLevel : undefined, - showLabel: !(basicStyle.showLabel === false), - WebGLParams: { - preserveDrawingBuffer: true - } - }) - }) - } else { - if (scene.getLayers()?.length) { - await scene.removeAllLayer() - scene.setPitch(miscStyle.mapPitch) - scene.setMapStyle(mapStyle) - scene.map.showLabel = !(basicStyle.showLabel === false) - } - if (basicStyle.autoFit === false) { - scene.setZoomAndCenter(basicStyle.zoomLevel, center) - } - } - mapRendering(container) - scene.once('loaded', () => { - mapRendered(container) - }) - this.configZoomButton(chart, scene) + scene = await getMapScene( + chart, + scene, + container, + mapKey, + basicStyle, + miscStyle, + mapStyle, + center + ) + + this.configZoomButton(chart, scene, mapKey) if (xAxis?.length < 2) { return new L7Wrapper(scene, undefined) } @@ -171,9 +147,13 @@ export class SymbolicMap extends L7ChartView { scene.addPopup(tooltipLayer) } this.buildLabel(chart, configList) + symbolicLayer.once('inited', () => { + mapRendered(container) + }) symbolicLayer.on('inited', () => { chart.container = container configCarouselTooltip(chart, symbolicLayer, symbolicLayer.sourceOption.data, scene) + qqMapRendered(scene) }) symbolicLayer.on('click', ev => { const data = ev.feature @@ -181,17 +161,17 @@ export class SymbolicMap extends L7ChartView { const quotaList = [] chart.data.fields.forEach((item, index) => { Object.keys(data).forEach(key => { - if (key.startsWith('f_') && item.dataeaseName === key) { + if (key.startsWith('f_') && item.gisbiName === key) { if (index === 0) { dimensionList.push({ id: item.id, - dataeaseName: item.dataeaseName, + gisbiName: item.gisbiName, value: data[key] }) } else { quotaList.push({ id: item.id, - dataeaseName: item.dataeaseName, + gisbiName: item.gisbiName, value: data[key] }) } @@ -239,7 +219,7 @@ export class SymbolicMap extends L7ChartView { let colorIndex = 0 // 存储已分配的颜色 const colorAssignments = new Map() - const sizeKey = extBubble.length > 0 ? extBubble[0].dataeaseName : '' + const sizeKey = extBubble.length > 0 ? extBubble[0].gisbiName : '' //条件颜色 const { threshold } = parseJson(chart.senior) @@ -257,7 +237,7 @@ export class SymbolicMap extends L7ChartView { ? chart.data.tableRow.map((item, index) => { item['_index'] = '_index' + index // 颜色标识 - const identifier = item[xAxisExt[0]?.dataeaseName] + const identifier = item[xAxisExt[0]?.gisbiName] // 检查该标识是否已有颜色分配,如果没有则分配 let color = colorAssignments.get(identifier) if (!color) { @@ -271,7 +251,7 @@ export class SymbolicMap extends L7ChartView { if (conditions.length > 0) { for (let i = 0; i < conditions.length; i++) { const c = conditions[i] - const value = item[c.field.dataeaseName] + const value = item[c.field.gisbiName] for (const t of c.conditions) { const v = t.value @@ -332,12 +312,12 @@ export class SymbolicMap extends L7ChartView { .source(data, { parser: { type: 'json', - x: xAxis[0].dataeaseName, - y: xAxis[1].dataeaseName + x: xAxis[0].gisbiName, + y: xAxis[1].gisbiName } }) .active(true) - if (xAxisExt[0]?.dataeaseName) { + if (xAxisExt[0]?.gisbiName) { if (basicStyle.mapSymbol === 'custom' && basicStyle.customIcon) { // 图片无法改色 if (basicStyle.customIcon.startsWith('data')) { @@ -452,8 +432,8 @@ export class SymbolicMap extends L7ChartView { let showFields = tooltip.showFields || [] if (!tooltip.showFields || tooltip.showFields.length === 0) { showFields = [ - ...chart.xAxisExt.map(i => `${i.dataeaseName}@${i.name}`), - ...chart.xAxis.map(i => `${i.dataeaseName}@${i.name}`) + ...chart.xAxisExt.map(i => `${i.gisbiName}@${i.name}`), + ...chart.xAxis.map(i => `${i.gisbiName}@${i.name}`) ] } // 修改背景色 @@ -584,8 +564,8 @@ export class SymbolicMap extends L7ChartView { let showFields = label.showFields || [] if (!label.showFields || label.showFields.length === 0) { showFields = [ - ...chart.xAxisExt.map(i => `${i.dataeaseName}@${i.name}`), - ...chart.xAxis.map(i => `${i.dataeaseName}@${i.name}`) + ...chart.xAxisExt.map(i => `${i.gisbiName}@${i.name}`), + ...chart.xAxis.map(i => `${i.gisbiName}@${i.name}`) ] } data.forEach(item => { @@ -613,8 +593,8 @@ export class SymbolicMap extends L7ChartView { .source(data, { parser: { type: 'json', - x: xAxis[0].dataeaseName, - y: xAxis[1].dataeaseName + x: xAxis[0].gisbiName, + y: xAxis[1].gisbiName } }) .shape('textLayerContent', 'text') diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/map/tooltip-carousel.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/map/tooltip-carousel.ts index 31616a8..d04c874 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/map/tooltip-carousel.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/map/tooltip-carousel.ts @@ -469,8 +469,8 @@ export class CarouselManager { }) } if (this.chart.type === 'symbolic-map') { - const lngField = this.chart.xAxis[0].dataeaseName - const latField = this.chart.xAxis[1].dataeaseName + const lngField = this.chart.xAxis[0].gisbiName + const latField = this.chart.xAxis[1].gisbiName const { _id } = this.scene ?.getLayers() ?.find(i => i.type === 'PointLayer') @@ -554,8 +554,8 @@ export class CarouselManager { let showFields = tooltip.showFields || [] if (!tooltip.showFields || tooltip.showFields.length === 0) { showFields = [ - ...this.chart.xAxisExt.map(i => `${i.dataeaseName}@${i.name}`), - ...this.chart.xAxis.map(i => `${i.dataeaseName}@${i.name}`) + ...this.chart.xAxisExt.map(i => `${i.gisbiName}@${i.name}`), + ...this.chart.xAxis.map(i => `${i.gisbiName}@${i.name}`) ] } const style = document.createElement('style') @@ -571,8 +571,8 @@ export class CarouselManager { } ` document.head.appendChild(style) - const lngField = this.chart.xAxis[0].dataeaseName - const latField = this.chart.xAxis[1].dataeaseName + const lngField = this.chart.xAxis[0].gisbiName + const latField = this.chart.xAxis[1].gisbiName const htmlPrefix = `
    ` const htmlSuffix = '
    ' const data = this.view.sourceOption.data[index] diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/others/chart-mix.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/others/chart-mix.ts index 0d2627a..0b19537 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/others/chart-mix.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/others/chart-mix.ts @@ -1,9 +1,10 @@ import { G2PlotChartView, G2PlotDrawOptions -} from '@/data-visualization/chart/components/js/panel/types/impl/g2plot' +} from '@/views/chart/components/js/panel/types/impl/g2plot' import type { DualAxes, DualAxesOptions } from '@antv/g2plot/esm/plots/dual-axes' import { + configRoundAngle, configPlotTooltipEvent, getAnalyse, getLabel, @@ -14,7 +15,7 @@ import { setGradientColor, TOOLTIP_TPL } from '../../common/common_antv' -import { flow, hexColorToRGBA, parseJson } from '@/data-visualization/chart/components/js/util' +import { flow, hexColorToRGBA, parseJson } from '@/views/chart/components/js/util' import { cloneDeep, isEmpty, @@ -25,7 +26,7 @@ import { defaultsDeep, defaults } from 'lodash-es' -import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' +import { valueFormatter } from '@/views/chart/components/js/formatter' import { CHART_MIX_AXIS_TYPE, CHART_MIX_DEFAULT_BASIC_STYLE, @@ -34,14 +35,15 @@ import { MixChartBasicStyle } from './chart-mix-common' import type { Datum } from '@antv/g2plot/esm/types/common' -import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { useI18n } from '@/hooks/web/useI18n' import { DEFAULT_BASIC_STYLE, DEFAULT_LABEL, DEFAULT_LEGEND_STYLE -} from '@/data-visualization/chart/components/editor/util/chart' +} from '@/views/chart/components/editor/util/chart' import type { Options } from '@antv/g2plot/esm' import { Group } from '@antv/g-canvas' +import { extremumEvt } from '@/views/chart/components/js/extremumUitl' const { t } = useI18n() const DEFAULT_DATA = [] @@ -56,7 +58,8 @@ export class ColumnLineMix extends G2PlotChartView { 'label-selector': ['vPosition', 'seriesLabelFormatter'], 'tooltip-selector': [ ...CHART_MIX_EDITOR_PROPERTY_INNER['tooltip-selector'], - 'seriesTooltipFormatter' + 'seriesTooltipFormatter', + 'carousel' ] } axis: AxisType[] = [...CHART_MIX_AXIS_TYPE, 'xAxisExtRight', 'yAxisExt'] @@ -94,6 +97,7 @@ export class ColumnLineMix extends G2PlotChartView { async drawChart(drawOptions: G2PlotDrawOptions): Promise { const { chart, action, container } = drawOptions + chart.container = container if (!chart.data?.left?.data?.length && !chart.data?.right?.data?.length) { return } @@ -117,7 +121,6 @@ export class ColumnLineMix extends G2PlotChartView { valueExt: d.value } }) - // options const initOptions: DualAxesOptions = { data: [data1, data2], @@ -127,6 +130,7 @@ export class ColumnLineMix extends G2PlotChartView { geometryOptions: [ { geometry: data1Type, + marginRatio: 0, color: [], isGroup: isGroup, isStack: isStack, @@ -174,6 +178,7 @@ export class ColumnLineMix extends G2PlotChartView { newChart.on('point:click', action) newChart.on('interval:click', action) + extremumEvt(newChart, chart, options, container) configPlotTooltipEvent(chart, newChart) return newChart } @@ -292,18 +297,9 @@ export class ColumnLineMix extends G2PlotChartView { tempOption.geometryOptions[1].smooth = smooth tempOption.geometryOptions[1].point = point tempOption.geometryOptions[1].lineStyle = lineStyle - - if (s.radiusColumnBar === 'roundAngle') { - const columnStyle = { - radius: [ - s.columnBarRightAngleRadius, - s.columnBarRightAngleRadius, - s.columnBarRightAngleRadius, - s.columnBarRightAngleRadius - ] - } - tempOption.geometryOptions[0].columnStyle = columnStyle - tempOption.geometryOptions[1].columnStyle = columnStyle + tempOption.geometryOptions[0] = { + ...tempOption.geometryOptions[0], + ...configRoundAngle(chart, 'columnStyle') } } @@ -328,7 +324,7 @@ export class ColumnLineMix extends G2PlotChartView { } setupDefaultOptions(chart: ChartObj): ChartObj { - const { customAttr, senior } = chart + const { senior } = chart if ( senior.functionCfg.emptyDataStrategy == undefined || senior.functionCfg.emptyDataStrategy === 'ignoreData' @@ -670,7 +666,8 @@ export class GroupColumnLineMix extends ColumnLineMix { 'label-selector': ['vPosition', 'seriesLabelFormatter'], 'tooltip-selector': [ ...CHART_MIX_EDITOR_PROPERTY_INNER['tooltip-selector'], - 'seriesTooltipFormatter' + 'seriesTooltipFormatter', + 'carousel' ] } axisConfig = { @@ -782,7 +779,8 @@ export class StackColumnLineMix extends ColumnLineMix { 'label-selector': ['vPosition', 'seriesLabelFormatter'], 'tooltip-selector': [ ...CHART_MIX_EDITOR_PROPERTY_INNER['tooltip-selector'], - 'seriesTooltipFormatter' + 'seriesTooltipFormatter', + 'carousel' ] } axisConfig = { @@ -895,7 +893,8 @@ export class DualLineMix extends ColumnLineMix { 'label-selector': ['seriesLabelFormatter'], 'tooltip-selector': [ ...CHART_MIX_EDITOR_PROPERTY_INNER['tooltip-selector'], - 'seriesTooltipFormatter' + 'seriesTooltipFormatter', + 'carousel' ] } axisConfig = { diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/others/circle-packing.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/others/circle-packing.ts index ab6bbad..fd0a1f6 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/others/circle-packing.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/others/circle-packing.ts @@ -69,7 +69,7 @@ export class CirclePacking extends G2PlotChartView @@ -123,7 +123,7 @@ export class CirclePacking extends G2PlotChartView { + newChart.on('element:click', param => { const pointData = param?.data?.data if (pointData?.name === t('commons.all')) { return @@ -157,7 +157,7 @@ export class CirclePacking extends G2PlotChartView { + formatter: (d: Datum) => { return d.children.length === 0 ? d.name : '' } } diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/others/gauge.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/others/gauge.ts index 1a98729..b338298 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/others/gauge.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/others/gauge.ts @@ -74,7 +74,7 @@ export class Gauge extends G2PlotChartView { // options const initOptions: GaugeOptions = { percent: 0, - appendPadding: getPadding(chart), + appendPadding: [0, 10, 15, 10], axis: { tickInterval: 0.2, label: { @@ -109,8 +109,10 @@ export class Gauge extends G2PlotChartView { } }) }) - const hasNoneData = chart.data?.series.some(s => !s.data?.[0]) - this.configEmptyDataStyle(newChart, hasNoneData ? [] : [1], container) + const hasNoneData = chart.data?.series.some( + s => s.data?.[0] === undefined || s.data?.[0] === null + ) + this.configEmptyDataStyle(hasNoneData ? [] : [1], container, newChart) if (hasNoneData) { return } diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/others/indicator.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/others/indicator.ts index c28611c..9befd68 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/others/indicator.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/others/indicator.ts @@ -15,7 +15,8 @@ export class IndicatorChartView extends AbstractChartView { 'indicator-value-selector', 'indicator-name-selector', 'threshold', - 'function-cfg' + 'function-cfg', + 'linkage' ] propertyInner: EditorPropertyInner = { 'background-overall-component': ['all'], diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/others/quadrant.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/others/quadrant.ts index d9d4e34..d9d1ec4 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/others/quadrant.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/others/quadrant.ts @@ -13,7 +13,8 @@ import { configPlotTooltipEvent, configYaxisTitleLengthLimit, getTooltipContainer, - TOOLTIP_TPL + TOOLTIP_TPL, + getPadding } from '../../common/common_antv' import { DEFAULT_LEGEND_STYLE } from '@/data-visualization/chart/components/editor/util/chart' @@ -209,7 +210,7 @@ export class Quadrant extends G2PlotChartView { data: data, xField: 'yAxis', yField: 'yAxisExt', - appendPadding: 30, + appendPadding: getPadding(chart), pointStyle: { fillOpacity: 0.8, stroke: '#bbb' @@ -476,7 +477,6 @@ export class Quadrant extends G2PlotChartView { this.configLegend, this.configXAxis, this.configYAxis, - this.configAnalyse, this.configSlider, this.configBasicStyle )(chart, options, {}, this) diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/others/sankey.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/others/sankey.ts index 783efa6..f751b9d 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/others/sankey.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/others/sankey.ts @@ -1,20 +1,20 @@ import { G2PlotChartView, G2PlotDrawOptions -} from '@/data-visualization/chart/components/js/panel/types/impl/g2plot' +} from '@/views/chart/components/js/panel/types/impl/g2plot' import type { Sankey, SankeyOptions } from '@antv/g2plot/esm/plots/sankey' -import { getPadding, setGradientColor } from '@/data-visualization/chart/components/js/panel/common/common_antv' +import { getPadding, setGradientColor } from '@/views/chart/components/js/panel/common/common_antv' import { cloneDeep, get } from 'lodash-es' -import { flow, hexColorToRGBA, parseJson } from '@/data-visualization/chart/components/js/util' -import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' +import { flow, hexColorToRGBA, parseJson } from '@/views/chart/components/js/util' +import { valueFormatter } from '@/views/chart/components/js/formatter' import { Datum } from '@antv/g2plot/esm/types/common' -import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { useI18n } from '@/hooks/web/useI18n' import { SANKEY_AXIS_TYPE, SANKEY_EDITOR_PROPERTY, SANKEY_EDITOR_PROPERTY_INNER -} from '@/data-visualization/chart/components/js/panel/charts/others/sankey-common' +} from '@/views/chart/components/js/panel/charts/others/sankey-common' const { t } = useI18n() const DEFAULT_DATA = [] diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/others/scatter.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/others/scatter.ts index a06684e..fafee87 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/others/scatter.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/others/scatter.ts @@ -14,6 +14,8 @@ import { import { useI18n } from '@/data-visualization/hooks/web/useI18n' import { defaults, isEmpty } from 'lodash-es' import { DEFAULT_LEGEND_STYLE } from '@/data-visualization/chart/components/editor/util/chart' +import { type Datum } from '@antv/g2plot/esm' +import { Group } from '@antv/g-canvas' const { t } = useI18n() /** @@ -144,6 +146,17 @@ export class Scatter extends G2PlotChartView { const { Scatter: G2Scatter } = await import('@antv/g2plot/esm/plots/scatter') const newChart = new G2Scatter(container, options) newChart.on('point:click', action) + if (options.label) { + newChart.on('label:click', e => { + action({ + x: e.x, + y: e.y, + data: { + data: e.target.attrs.data + } + }) + }) + } configPlotTooltipEvent(chart, newChart) return newChart } @@ -277,6 +290,41 @@ export class Scatter extends G2PlotChartView { return optionTmp } + protected configLabel(chart: Chart, options: ScatterOptions): ScatterOptions { + const tmpOption = super.configLabel(chart, options) + if (!tmpOption.label) { + return options + } + const { label: labelAttr } = parseJson(chart.customAttr) + tmpOption.label.style.fill = labelAttr.color + const label = { + ...tmpOption.label, + formatter: function (data: Datum) { + const value = valueFormatter(data.value, labelAttr.labelFormatter) + const group = new Group({}) + group.addShape({ + type: 'text', + attrs: { + x: 0, + y: 0, + data, + text: value, + textAlign: 'start', + textBaseline: 'top', + fontSize: labelAttr.fontSize, + fontFamily: chart.fontFamily, + fill: labelAttr.color + } + }) + return group + } + } + return { + ...tmpOption, + label + } + } + protected setupOptions(chart: Chart, options: ScatterOptions) { return flow( this.configTheme, @@ -286,7 +334,6 @@ export class Scatter extends G2PlotChartView { this.configLegend, this.configXAxis, this.configYAxis, - this.configAnalyse, this.configSlider, this.configBasicStyle )(chart, options) diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/others/word-cloud.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/others/word-cloud.ts index 0baf181..ec5a992 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/others/word-cloud.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/others/word-cloud.ts @@ -1,19 +1,19 @@ import { G2PlotChartView, G2PlotDrawOptions -} from '@/data-visualization/chart/components/js/panel/types/impl/g2plot' +} from '@/views/chart/components/js/panel/types/impl/g2plot' import type { WordCloud as G2WordCloud, WordCloudOptions } from '@antv/g2plot/esm/plots/word-cloud' import { filterChartDataByRange, flow, getMaxAndMinValueByData, parseJson -} from '@/data-visualization/chart/components/js/util' -import { getPadding } from '@/data-visualization/chart/components/js/panel/common/common_antv' -import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' -import { useI18n } from '@/data-visualization/hooks/web/useI18n' +} from '@/views/chart/components/js/util' +import { getPadding } from '@/views/chart/components/js/panel/common/common_antv' +import { valueFormatter } from '@/views/chart/components/js/formatter' +import { useI18n } from '@/hooks/web/useI18n' import { isEmpty } from 'lodash-es' -import { DEFAULT_MISC } from '@/data-visualization/chart/components/editor/util/chart' +import { DEFAULT_MISC } from '@/views/chart/components/editor/util/chart' const { t } = useI18n() const DEFAULT_DATA = [] diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/pie/pie.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/pie/pie.ts index 0263080..b689753 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/pie/pie.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/pie/pie.ts @@ -27,19 +27,23 @@ import type { Datum } from '@antv/g2plot/esm/types/common' import { add } from 'mathjs' import isEmpty from 'lodash-es/isEmpty' import { cloneDeep } from 'lodash-es' - +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +const { t } = useI18n() const DEFAULT_DATA = [] export class Pie extends G2PlotChartView { axis: AxisType[] = PIE_AXIS_TYPE properties = PIE_EDITOR_PROPERTY propertyInner: EditorPropertyInner = { ...PIE_EDITOR_PROPERTY_INNER, - 'basic-style-selector': ['colors', 'alpha', 'radius', 'topN', 'seriesColor'] + 'basic-style-selector': ['colors', 'alpha', 'radius', 'topN', 'seriesColor'], + 'tooltip-selector': [...PIE_EDITOR_PROPERTY_INNER['tooltip-selector'], 'carousel'] } axisConfig = PIE_AXIS_CONFIG async drawChart(drawOptions: G2PlotDrawOptions): Promise { const { chart, container, action } = drawOptions + this.configEmptyDataStyle(chart.data?.data, container, null, t('chart.no_data_or_not_positive')) + chart.container = container if (!chart.data?.data?.length) { return } @@ -115,12 +119,22 @@ export class Pie extends G2PlotChartView { field: { type: 'cat' } + }, + state: { + active: { + style: { + lineWidth: 2, + fillOpacity: 0.5 + } + } } } const options = this.setupOptions(chart, initOptions) const { Pie: G2Pie } = await import('@antv/g2plot/esm/plots/pie') const newChart = new G2Pie(container, options) - newChart.on('interval:click', action) + newChart.on('interval:click', d => { + d.data?.data?.field !== customAttr.basicStyle.topNLabel && action(d) + }) configPlotTooltipEvent(chart, newChart) return newChart } @@ -244,6 +258,7 @@ export class Pie extends G2PlotChartView { }, container: getTooltipContainer(`tooltip-${chart.id}`), itemTpl: TOOLTIP_TPL, + shared: true, enterable: true } return { @@ -338,7 +353,8 @@ export class Pie extends G2PlotChartView { export class PieDonut extends Pie { propertyInner: EditorPropertyInner = { ...PIE_EDITOR_PROPERTY_INNER, - 'basic-style-selector': ['colors', 'alpha', 'radius', 'innerRadius', 'topN', 'seriesColor'] + 'basic-style-selector': ['colors', 'alpha', 'radius', 'innerRadius', 'topN', 'seriesColor'], + 'tooltip-selector': [...PIE_EDITOR_PROPERTY_INNER['tooltip-selector'], 'carousel'] } protected configBasicStyle(chart: Chart, options: PieOptions): PieOptions { const tmp = super.configBasicStyle(chart, options) diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/pie/rose.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/pie/rose.ts index 0432ca7..d9aa4b6 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/pie/rose.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/pie/rose.ts @@ -40,6 +40,7 @@ export class Rose extends G2PlotChartView { async drawChart(drawOptions: G2PlotDrawOptions): Promise { const { chart, container, action } = drawOptions + this.configEmptyDataStyle(chart.data?.data, container, null, t('chart.no_data_or_not_positive')) if (!chart?.data?.data?.length) { return } diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/table/common.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/table/common.ts index 08b146e..eb1ecf1 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/table/common.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/table/common.ts @@ -6,6 +6,7 @@ export const TABLE_EDITOR_PROPERTY: EditorProperty[] = [ 'table-cell-selector', 'title-selector', 'tooltip-selector', + 'summary-selector', 'function-cfg', 'threshold', 'scroll-cfg', diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/table/dist/t-heatmap.js b/frontend/src/data-visualization/chart/components/js/panel/charts/table/dist/t-heatmap.js new file mode 100644 index 0000000..1ef2194 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/table/dist/t-heatmap.js @@ -0,0 +1,402 @@ +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var __spreadArrays = (this && this.__spreadArrays) || function () { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; + for (var r = Array(s), k = 0, i = 0; i < il; i++) + for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) + r[k] = a[j]; + return r; +}; +exports.__esModule = true; +exports.TableHeatmap = void 0; +var g2plot_1 = require("@/views/chart/components/js/panel/types/impl/g2plot"); +var util_1 = require("@/views/chart/components/js/util"); +var useI18n_1 = require("@/hooks/web/useI18n"); +var utils_1 = require("@/utils/utils"); +var lodash_es_1 = require("lodash-es"); +var common_antv_1 = require("@/views/chart/components/js/panel/common/common_antv"); +var formatter_1 = require("@/views/chart/components/js/formatter"); +var t = useI18n_1.useI18n().t; +var DEFAULT_DATA = []; +/** + * 热力图 + */ +var TableHeatmap = /** @class */ (function (_super) { + __extends(TableHeatmap, _super); + function TableHeatmap() { + var _this = _super.call(this, 't-heatmap', DEFAULT_DATA) || this; + _this.properties = [ + 'basic-style-selector', + 'background-overall-component', + 'label-selector', + 'legend-selector', + 'x-axis-selector', + 'y-axis-selector', + 'title-selector', + 'tooltip-selector', + 'jump-set', + 'linkage', + 'border-style' + ]; + _this.propertyInner = { + 'background-overall-component': ['all'], + 'basic-style-selector': ['colors'], + 'label-selector': ['fontSize', 'color'], + 'x-axis-selector': ['name', 'color', 'fontSize', 'position', 'axisLabel', 'axisLine'], + 'y-axis-selector': [ + 'name', + 'color', + 'fontSize', + 'position', + 'axisLabel', + 'axisLine', + 'showLengthLimit' + ], + 'title-selector': [ + 'title', + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'remarkShow', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ], + 'legend-selector': ['orient', 'color', 'fontSize', 'hPosition', 'vPosition'], + 'tooltip-selector': ['show', 'color', 'fontSize', 'backgroundColor'], + 'border-style': ['all'] + }; + _this.axis = ['xAxis', 'xAxisExt', 'extColor', 'filter']; + _this.axisConfig = { + xAxis: { + name: t('chart.x_axis') + " / " + t('chart.dimension'), + type: 'd', + limit: 1 + }, + xAxisExt: { + name: t('chart.y_axis') + " / " + t('chart.dimension'), + type: 'd', + limit: 1 + }, + extColor: { + name: t('chart.color') + " / " + t('chart.dimension_or_quota'), + limit: 1 + } + }; + _this.getDefaultLength = function (chart, l) { + var containerDom = document.getElementById(chart.container); + var containerHeight = (containerDom === null || containerDom === void 0 ? void 0 : containerDom.clientHeight) || 100; + var containerWidth = (containerDom === null || containerDom === void 0 ? void 0 : containerDom.clientWidth) || 100; + var defaultLength = containerHeight - containerHeight * 0.5; + if (l.orient !== 'vertical') { + defaultLength = containerWidth - containerWidth * 0.5; + } + return defaultLength; + }; + _this.sortData = function (fieldObj, data) { + var deType = fieldObj.deType, sort = fieldObj.sort, customSort = fieldObj.customSort; + if (sort === 'desc') { + if (deType === 0) { + return data.sort().reverse(); + } + else { + return data.sort(function (a, b) { return b - a; }); + } + } + else if (sort === 'asc') { + if (deType === 0) { + return data.sort(); + } + else { + return data.sort(function (a, b) { return a - b; }); + } + } + // 如果没有指定排序方式,直接返回原始数据或 customSort + return customSort && customSort.length > 0 ? customSort : data; + }; + return _this; + } + TableHeatmap.prototype.drawChart = function (drawOptions) { + return __awaiter(this, void 0, Promise, function () { + var chart, container, action, xAxis, xAxisExt, extColor, xField, xFieldExt, extColorField, tmpData, data, initOptions, options, Heatmap, newChart; + var _a; + var _this = this; + return __generator(this, function (_b) { + switch (_b.label) { + case 0: + chart = drawOptions.chart, container = drawOptions.container, action = drawOptions.action; + xAxis = utils_1.deepCopy(chart.xAxis); + xAxisExt = utils_1.deepCopy(chart.xAxisExt); + extColor = utils_1.deepCopy(chart.extColor); + if (!(xAxis === null || xAxis === void 0 ? void 0 : xAxis.length) || !(xAxisExt === null || xAxisExt === void 0 ? void 0 : xAxisExt.length) || !(extColor === null || extColor === void 0 ? void 0 : extColor.length)) { + return [2 /*return*/]; + } + xField = xAxis[0].gisbiName; + xFieldExt = xAxisExt[0].gisbiName; + extColorField = extColor[0].gisbiName; + tmpData = lodash_es_1.cloneDeep(chart.data.tableRow); + data = tmpData.filter(function (cell) { return cell[xField] && cell[xFieldExt] && cell[extColorField]; }); + data.forEach(function (i) { + Object.keys(i).forEach(function (key) { + if (key === '*') { + i['@'] = i[key]; + } + }); + }); + initOptions = { + data: data, + xField: xField, + yField: xFieldExt, + colorField: extColorField === '*' ? '@' : extColorField, + appendPadding: common_antv_1.getPadding(chart), + meta: (_a = {}, + _a[xField] = { + type: 'cat', + values: this.sortData(xAxis[0], __spreadArrays(new Set(data.map(function (i) { return i[[xField]]; })))) + }, + _a[xFieldExt] = { + type: 'cat', + values: this.sortData(xAxisExt[0], __spreadArrays(new Set(data.map(function (i) { return i[[xFieldExt]]; })))).reverse() + }, + _a), + legend: { + layout: 'vertical', + position: 'right', + slidable: true, + label: { + align: 'left', + spacing: 10 + } + } + }; + chart.container = container; + options = this.setupOptions(chart, initOptions); + return [4 /*yield*/, Promise.resolve().then(function () { return require('@antv/g2plot/esm/plots/heatmap'); })]; + case 1: + Heatmap = (_b.sent()).Heatmap; + newChart = new Heatmap(container, options); + newChart.on('plot:click', function (param) { + var _a; + if (!((_a = param.data) === null || _a === void 0 ? void 0 : _a.data)) { + return; + } + var pointData = param.data.data; + var dimensionList = []; + chart.data.fields.forEach(function (item) { + Object.keys(pointData).forEach(function (key) { + if (key.startsWith('f_') && item.gisbiName === key) { + dimensionList.push({ + id: item.id, + gisbiName: item.gisbiName, + value: pointData[key] + }); + } + }); + }); + action({ + x: param.data.x, + y: param.data.y, + data: { + data: __assign(__assign({}, param.data.data), { value: dimensionList[1].value, name: dimensionList[1].id, dimensionList: dimensionList, quotaList: [dimensionList[1]] }) + } + }); + }); + newChart.on('afterrender', function (ev) { + var _a; + var l = JSON.parse(JSON.stringify(util_1.parseJson(chart.customStyle).legend)); + if (l.show) { + var rail = (_a = ev.view.getController('legend').option[extColor[0].gisbiName]) === null || _a === void 0 ? void 0 : _a['rail']; + if (rail) { + rail.defaultLength = _this.getDefaultLength(chart, l); + } + } + }); + common_antv_1.configAxisLabelLengthLimit(chart, newChart); + return [2 /*return*/, newChart]; + } + }); + }); + }; + TableHeatmap.prototype.configTheme = function (chart, options) { + var tmp = _super.prototype.configTheme.call(this, chart, options); + tmp.theme.innerLabels.offset = 0; + return tmp; + }; + TableHeatmap.prototype.configBasicStyle = function (chart, options) { + var _a; + var basicStyle = util_1.parseJson(chart.customAttr).basicStyle; + var color = (_a = basicStyle.colors) === null || _a === void 0 ? void 0 : _a.map(function (ele) { + return util_1.hexColorToRGBA(ele, basicStyle.alpha); + }); + return __assign(__assign({}, options), { color: color }); + }; + TableHeatmap.prototype.configTooltip = function (chart, options) { + var tooltip; + var customAttr; + if (chart.customAttr) { + customAttr = util_1.parseJson(chart.customAttr); + // tooltip + if (customAttr.tooltip) { + var extColor = utils_1.deepCopy(chart.extColor); + var xAxisExt = utils_1.deepCopy(chart.xAxisExt); + var tooltipFiledList_1 = [xAxisExt, extColor]; + var t_1 = JSON.parse(JSON.stringify(customAttr.tooltip)); + if (t_1.show) { + tooltip = { + showTitle: true, + customItems: function (originalItems) { + var items = []; + var createItem = function (fieldObj, items, originalItems) { + var name = (fieldObj === null || fieldObj === void 0 ? void 0 : fieldObj.chartShowName) ? fieldObj === null || fieldObj === void 0 ? void 0 : fieldObj.chartShowName : fieldObj === null || fieldObj === void 0 ? void 0 : fieldObj.name; + var value = originalItems[0].data[fieldObj.gisbiName]; + if (!isNaN(Number(value))) { + value = formatter_1.valueFormatter(value, fieldObj === null || fieldObj === void 0 ? void 0 : fieldObj.formatterCfg); + } + items.push(__assign(__assign({}, originalItems[0]), { name: name, value: value })); + }; + tooltipFiledList_1.forEach(function (field) { + createItem(field[0], items, originalItems); + }); + return items; + } + }; + } + else { + tooltip = false; + } + } + } + return __assign(__assign({}, options), { tooltip: tooltip }); + }; + TableHeatmap.prototype.configXAxis = function (chart, options) { + var xAxis = common_antv_1.getXAxis(chart); + return __assign(__assign({}, options), { xAxis: xAxis ? __assign(__assign({}, xAxis), { grid: null }) : false }); + }; + TableHeatmap.prototype.configYAxis = function (chart, options) { + var yAxis = common_antv_1.getYAxis(chart); + return __assign(__assign({}, options), { yAxis: yAxis ? __assign(__assign({}, yAxis), { grid: null }) : false }); + }; + TableHeatmap.prototype.configLegend = function (chart, options) { + var tmpOptions = _super.prototype.configLegend.call(this, chart, options); + if (tmpOptions.legend) { + var l = JSON.parse(JSON.stringify(util_1.parseJson(chart.customStyle).legend)); + tmpOptions.legend.slidable = true; + tmpOptions.legend.minHeight = 10; + tmpOptions.legend.minWidth = 10; + tmpOptions.legend.maxHeight = 600; + tmpOptions.legend.maxWidth = 600; + var containerDom = document.getElementById(chart.container); + var containerHeight = (containerDom === null || containerDom === void 0 ? void 0 : containerDom.clientHeight) || 100; + var containerWidth = (containerDom === null || containerDom === void 0 ? void 0 : containerDom.clientWidth) || 100; + var defaultLength = containerHeight - containerHeight * 0.5; + if (l.orient === 'vertical') { + tmpOptions.legend.offsetY = -5; + } + else { + defaultLength = containerWidth - containerWidth * 0.5; + } + tmpOptions.legend.rail = { defaultLength: defaultLength }; + tmpOptions.legend.label = { + spacing: 10, + style: { + fill: l.color, + fontSize: l.fontSize + } + }; + } + return tmpOptions; + }; + TableHeatmap.prototype.setupDefaultOptions = function (chart) { + chart.customStyle.legend.orient = 'vertical'; + chart.customStyle.legend.vPosition = 'center'; + chart.customStyle.legend.hPosition = 'right'; + chart.customStyle.legend['rail'] = { defaultLength: 100 }; + return chart; + }; + TableHeatmap.prototype.configLabel = function (chart, options) { + var tmpOptions = _super.prototype.configLabel.call(this, chart, options); + if (tmpOptions.label) { + var extColor_1 = utils_1.deepCopy(chart.extColor); + var layout = []; + if (!tmpOptions.label.fullDisplay) { + layout.push.apply(layout, tmpOptions.label.layout); + } + var label = __assign(__assign({}, tmpOptions.label), { position: 'middle', layout: layout, formatter: function (data) { + var _a, _b; + var value = data[(_a = extColor_1[0]) === null || _a === void 0 ? void 0 : _a.gisbiName]; + if (!isNaN(Number(value))) { + return formatter_1.valueFormatter(value, (_b = extColor_1[0]) === null || _b === void 0 ? void 0 : _b.formatterCfg); + } + return value; + } }); + return __assign(__assign({}, tmpOptions), { label: label }); + } + return tmpOptions; + }; + TableHeatmap.prototype.setupOptions = function (chart, options) { + return util_1.flow(this.configTheme, this.configXAxis, this.configYAxis, this.configBasicStyle, this.configLegend, this.configTooltip, this.configLabel)(chart, options); + }; + return TableHeatmap; +}(g2plot_1.G2PlotChartView)); +exports.TableHeatmap = TableHeatmap; diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/table/dist/table-info.js b/frontend/src/data-visualization/chart/components/js/panel/charts/table/dist/table-info.js new file mode 100644 index 0000000..52f39c7 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/table/dist/table-info.js @@ -0,0 +1,564 @@ +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __spreadArrays = (this && this.__spreadArrays) || function () { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; + for (var r = Array(s), k = 0, i = 0; i < il; i++) + for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) + r[k] = a[j]; + return r; +}; +exports.__esModule = true; +exports.TableInfo = void 0; +var s2_1 = require("@antv/s2"); +var formatter_1 = require("../../../formatter"); +var util_1 = require("../../../util"); +var s2_2 = require("../../types/impl/s2"); +var common_1 = require("./common"); +var useI18n_1 = require("@/hooks/web/useI18n"); +var lodash_es_1 = require("lodash-es"); +var common_table_1 = require("@/views/chart/components/js/panel/common/common_table"); +var t = useI18n_1.useI18n().t; +var ImageCell = /** @class */ (function (_super) { + __extends(ImageCell, _super); + function ImageCell() { + return _super !== null && _super.apply(this, arguments) || this; + } + ImageCell.prototype.drawTextShape = function () { + common_table_1.drawImage.apply(this); + }; + return ImageCell; +}(common_table_1.CustomDataCell)); +/** + * 明细表 + */ +var TableInfo = /** @class */ (function (_super) { + __extends(TableInfo, _super); + function TableInfo() { + var _this = _super.call(this, 'table-info', []) || this; + _this.properties = common_1.TABLE_EDITOR_PROPERTY; + _this.propertyInner = __assign(__assign({}, common_1.TABLE_EDITOR_PROPERTY_INNER), { 'table-header-selector': __spreadArrays(common_1.TABLE_EDITOR_PROPERTY_INNER['table-header-selector'], [ + 'tableHeaderSort', + 'showTableHeader', + 'headerGroup' + ]), 'basic-style-selector': [ + 'tableColumnMode', + 'tableBorderColor', + 'tableScrollBarColor', + 'alpha', + 'tablePageMode', + 'showHoverStyle', + 'autoWrap' + ], 'table-cell-selector': __spreadArrays(common_1.TABLE_EDITOR_PROPERTY_INNER['table-cell-selector'], [ + 'tableFreeze', + 'tableColumnFreezeHead', + 'tableRowFreezeHead', + 'mergeCells' + ]), 'summary-selector': ['showSummary', 'summaryLabel'] }); + _this.axis = ['xAxis', 'filter', 'drill']; + _this.axisConfig = { + xAxis: { + name: t('chart.drag_block_table_data_column') + " / " + t('chart.dimension_or_quota') + } + }; + return _this; + } + TableInfo.prototype.drawChart = function (drawOption) { + var _this = this; + var _a, _b, _c, _d, _e; + var container = drawOption.container, chart = drawOption.chart, pageInfo = drawOption.pageInfo, action = drawOption.action, resizeAction = drawOption.resizeAction; + var containerDom = document.getElementById(container); + // fields + var fields = (_b = (_a = chart.data) === null || _a === void 0 ? void 0 : _a.fields) !== null && _b !== void 0 ? _b : []; + var columns = []; + var meta = []; + var axisMap = chart.xAxis.reduce(function (pre, cur) { + pre[cur.gisbiName] = cur; + return pre; + }, {}); + var drillFieldMap = {}; + if (chart.drill) { + // 下钻过滤字段 + var filterFields_1 = chart.drillFilters.map(function (i) { return i.fieldId; }); + // 下钻入口的字段下标 + var drillFieldId_1 = chart.drillFields[0].id; + var drillFieldIndex = chart.xAxis.findIndex(function (ele) { return ele.id === drillFieldId_1; }); + // 当前下钻字段 + var curDrillFieldId_1 = chart.drillFields[filterFields_1.length].id; + var curDrillField = fields.find(function (ele) { return ele.id === curDrillFieldId_1; }); + filterFields_1.push(curDrillFieldId_1); + // 移除下钻字段,把当前下钻字段插入到下钻入口位置 + fields = fields.filter(function (ele) { + return !filterFields_1.includes(ele.id); + }); + drillFieldMap[curDrillField.gisbiName] = chart.drillFields[0].gisbiName; + fields.splice(drillFieldIndex, 0, curDrillField); + } + fields.forEach(function (ele) { + var _a; + var f = axisMap[ele.gisbiName]; + if ((f === null || f === void 0 ? void 0 : f.hide) === true) { + return; + } + columns.push(ele.gisbiName); + meta.push({ + field: ele.gisbiName, + name: (_a = ele.chartShowName) !== null && _a !== void 0 ? _a : ele.name, + formatter: function (value) { + if (!f) { + return value; + } + if (value === null || value === undefined) { + return value; + } + if (![2, 3, 4].includes(f.deType) || !lodash_es_1.isNumber(value)) { + return value; + } + var formatCfg = f.formatterCfg; + if (!formatCfg) { + formatCfg = formatter_1.formatterItem; + } + return formatter_1.valueFormatter(value, formatCfg); + } + }); + }); + var _f = util_1.parseJson(chart.customAttr), basicStyle = _f.basicStyle, tableCell = _f.tableCell, tableHeader = _f.tableHeader, tooltip = _f.tooltip; + // 表头分组 + var headerGroup = tableHeader.headerGroup, showTableHeader = tableHeader.showTableHeader; + if (headerGroup && showTableHeader !== false) { + var headerGroupConfig = tableHeader.headerGroupConfig; + if ((_c = headerGroupConfig === null || headerGroupConfig === void 0 ? void 0 : headerGroupConfig.columns) === null || _c === void 0 ? void 0 : _c.length) { + var allKeys = columns.map(function (c) { return drillFieldMap[c] || c; }); + var leafNodes = common_table_1.getLeafNodes(headerGroupConfig.columns); + var leafKeys = leafNodes.map(function (c) { return c.key; }); + if (lodash_es_1.isEqual(leafKeys, allKeys)) { + if (Object.keys(drillFieldMap).length) { + var originField = Object.values(drillFieldMap)[0]; + var drillField = Object.keys(drillFieldMap)[0]; + var drillCol = common_table_1.getColumns([originField], headerGroupConfig.columns)[0]; + drillCol.key = drillField; + } + columns.splice.apply(columns, __spreadArrays([0, columns.length], headerGroupConfig.columns)); + meta.push.apply(meta, headerGroupConfig.meta); + } + } + } + // 空值处理 + var newData = this.configEmptyDataStrategy(chart); + // data config + var s2DataConfig = { + fields: { + columns: columns + }, + meta: meta, + data: newData + }; + // options + var s2Options = { + width: containerDom.getBoundingClientRect().width, + height: containerDom.offsetHeight, + showSeriesNumber: tableHeader.showIndex, + conditions: this.configConditions(chart), + tooltip: { + getContainer: function () { return containerDom; }, + renderTooltip: function (sheet) { return new common_table_1.SortTooltip(sheet); } + }, + interaction: { + hoverHighlight: !(basicStyle.showHoverStyle === false), + scrollbarPosition: newData.length + ? s2_1.ScrollbarPositionType.CONTENT + : s2_1.ScrollbarPositionType.CANVAS + } + }; + s2Options.style = this.configStyle(chart, s2DataConfig); + // 自适应列宽模式下,URL 字段的宽度固定为 120 + if (basicStyle.tableColumnMode === 'adapt') { + var urlFields = fields.filter(function (field) { var _a; return field.deType === 7 && !((_a = axisMap[field.gisbiName]) === null || _a === void 0 ? void 0 : _a.hide); }); + s2Options.style.colCfg.widthByFieldValue = urlFields === null || urlFields === void 0 ? void 0 : urlFields.reduce(function (p, n) { + var _a; + p[(_a = n.chartShowName) !== null && _a !== void 0 ? _a : n.name] = 120; + return p; + }, {}); + } + if (tableCell.tableFreeze && !tableCell.mergeCells) { + s2Options.frozenColCount = (_d = tableCell.tableColumnFreezeHead) !== null && _d !== void 0 ? _d : 0; + s2Options.frozenRowCount = (_e = tableCell.tableRowFreezeHead) !== null && _e !== void 0 ? _e : 0; + } + // tooltip + this.configTooltip(chart, s2Options); + // 合并单元格 + this.configMergeCells(chart, s2Options, s2DataConfig); + // 隐藏表头,保留顶部的分割线, 禁用表头横向 resize + if (tableHeader.showTableHeader === false) { + s2Options.style.colCfg.height = 1; + if (tableCell.showHorizonBorder === false) { + s2Options.style.colCfg.height = 0; + } + s2Options.interaction.resize = { + colCellVertical: false + }; + s2Options.colCell = function (node, sheet, config) { + node.label = ' '; + return new s2_1.TableColCell(node, sheet, config); + }; + } + else { + // header interaction + chart.container = container; + this.configHeaderInteraction(chart, s2Options); + s2Options.colCell = function (node, sheet, config) { + // 配置文本自动换行参数 + node.autoWrap = tableCell.mergeCells ? false : basicStyle.autoWrap; + node.maxLines = basicStyle.maxLines; + return new common_table_1.CustomTableColCell(node, sheet, config); + }; + } + // 序列号和总计行 + this.configSummaryRowAndIndex(chart, pageInfo, s2Options, s2DataConfig); + // 开始渲染 + var newChart = new s2_1.TableSheet(containerDom, s2DataConfig, s2Options); + // 总计紧贴在单元格后面 + this.summaryRowStyle(newChart, newData, tableCell, tableHeader, basicStyle.showSummary); + // 开启自动换行 + if (basicStyle.autoWrap && !tableCell.mergeCells) { + // 调整表头宽度时,计算表头高度 + newChart.on(s2_1.S2Event.LAYOUT_RESIZE_COL_WIDTH, function (info) { + common_table_1.calculateHeaderHeight(info, newChart, tableHeader, basicStyle, null); + }); + newChart.on(s2_1.S2Event.LAYOUT_AFTER_HEADER_LAYOUT, function (ev) { + var _a; + var maxHeight = newChart.store.get('autoCalcHeight'); + if (maxHeight) { + // 更新列的高度 + ev.colLeafNodes.forEach(function (n) { return (n.height = maxHeight); }); + ev.colsHierarchy.height = maxHeight; + newChart.store.set('autoCalcHeight', undefined); + } + else { + if ((_a = ev.colLeafNodes) === null || _a === void 0 ? void 0 : _a.length) { + var _b = ev.colLeafNodes[0], value = _b.value, width = _b.width; + common_table_1.calculateHeaderHeight({ info: { meta: { value: value }, resizedWidth: width } }, newChart, tableHeader, basicStyle, ev); + } + } + }); + } + // 自适应铺满 + if (basicStyle.tableColumnMode === 'adapt') { + newChart.on(s2_1.S2Event.LAYOUT_RESIZE_COL_WIDTH, function () { + newChart.store.set('lastLayoutResult', newChart.facet.layoutResult); + }); + newChart.on(s2_1.S2Event.LAYOUT_AFTER_HEADER_LAYOUT, function (ev) { + var _a, _b; + var lastLayoutResult = newChart.store.get('lastLayoutResult'); + if (lastLayoutResult) { + // 拖动表头 resize + var widthByFieldValue_1 = (_b = (_a = newChart.options.style) === null || _a === void 0 ? void 0 : _a.colCfg) === null || _b === void 0 ? void 0 : _b.widthByFieldValue; + var lastLayoutWidthMap_1 = (lastLayoutResult === null || lastLayoutResult === void 0 ? void 0 : lastLayoutResult.colLeafNodes.reduce(function (p, n) { + var _a; + p[n.value] = (_a = widthByFieldValue_1 === null || widthByFieldValue_1 === void 0 ? void 0 : widthByFieldValue_1[n.value]) !== null && _a !== void 0 ? _a : n.width; + return p; + }, {})) || {}; + var totalWidth_1 = ev.colLeafNodes.reduce(function (p, n) { + n.width = lastLayoutWidthMap_1[n.value] || n.width; + n.x = p; + return p + n.width; + }, 0); + // 处理分组的单元格,宽度为所有叶子节点之和 + ev.colNodes.forEach(function (n) { + if (n.colIndex === -1) { + n.width = calcTreeWidth(n); + n.x = getStartPosition(n); + } + }); + ev.colsHierarchy.width = totalWidth_1; + newChart.store.set('lastLayoutResult', undefined); + return; + } + // 第一次渲染初始化,把图片字段固定为 120 进行计算 + var urlFields = fields + .filter(function (field) { var _a; return field.deType === 7 && !((_a = axisMap[field.gisbiName]) === null || _a === void 0 ? void 0 : _a.hide); }) + .map(function (f) { return f.gisbiName; }); + var totalWidthWithImg = ev.colLeafNodes.reduce(function (p, n) { + return p + (urlFields.includes(n.field) ? 120 : n.width); + }, 0); + var containerWidth = containerDom.getBoundingClientRect().width; + if (containerWidth <= totalWidthWithImg) { + // 图库计算的布局宽度已经大于等于容器宽度,不需要再扩大,但是需要处理非整数宽度值,不然会出现透明细线 + ev.colLeafNodes.reduce(function (p, n) { + n.width = Math.round(n.width); + n.x = p; + return p + n.width; + }, 0); + return; + } + // 图片字段固定 120, 剩余宽度按比例均摊到其他字段进行扩大 + var totalWidthWithoutImg = ev.colLeafNodes.reduce(function (p, n) { + return p + (urlFields.includes(n.field) ? 0 : n.width); + }, 0); + var restWidth = containerWidth - urlFields.length * 120; + var scale = restWidth / totalWidthWithoutImg; + var totalWidth = ev.colLeafNodes.reduce(function (p, n) { + n.width = urlFields.includes(n.field) ? 120 : Math.round(n.width * scale); + n.x = p; + return p + n.width; + }, 0); + // 处理分组的单元格,宽度为所有叶子节点之和 + ev.colNodes.forEach(function (n) { + if (n.colIndex === -1) { + n.width = calcTreeWidth(n); + n.x = getStartPosition(n); + } + }); + if (totalWidth > containerWidth) { + ev.colLeafNodes[ev.colLeafNodes.length - 1].width -= totalWidth - containerWidth; + } + ev.colsHierarchy.width = containerWidth; + }); + } + // 空数据时表格样式 + common_table_1.configEmptyDataStyle(newChart, basicStyle, newData, container); + // click + newChart.on(s2_1.S2Event.DATA_CELL_CLICK, function (ev) { + var cell = newChart.getCell(ev.target); + var meta = cell.getMeta(); + var nameIdMap = fields.reduce(function (pre, next) { + pre[next['gisbiName']] = next['id']; + return pre; + }, {}); + var rowData = newChart.dataSet.getRowData(meta); + var dimensionList = []; + for (var key in rowData) { + if (nameIdMap[key]) { + dimensionList.push({ id: nameIdMap[key], value: rowData[key] }); + } + } + var param = { + x: ev.x, + y: ev.y, + data: { + dimensionList: dimensionList, + name: nameIdMap[meta.valueField], + sourceType: 'table-info', + quotaList: [] + } + }; + action(param); + }); + // 合并的单元格直接复用数据单元格的事件 + newChart.on(s2_1.S2Event.MERGED_CELLS_CLICK, function (e) { return newChart.emit(s2_1.S2Event.DATA_CELL_CLICK, e); }); + // tooltip + var show = tooltip.show; + if (show) { + newChart.on(s2_1.S2Event.COL_CELL_HOVER, function (event) { return _this.showTooltip(newChart, event, meta); }); + newChart.on(s2_1.S2Event.DATA_CELL_HOVER, function (event) { return _this.showTooltip(newChart, event, meta); }); + newChart.on(s2_1.S2Event.MERGED_CELLS_HOVER, function (event) { return _this.showTooltip(newChart, event, meta); }); + // touch + this.configTouchEvent(newChart, drawOption, meta); + } + // header resize + newChart.on(s2_1.S2Event.LAYOUT_RESIZE_COL_WIDTH, function (ev) { return resizeAction(ev); }); + // right click + newChart.on(s2_1.S2Event.GLOBAL_CONTEXT_MENU, function (event) { return common_table_1.copyContent(newChart, event, meta); }); + // theme + var customTheme = this.configTheme(chart); + newChart.setThemeCfg({ theme: customTheme }); + return newChart; + }; + TableInfo.prototype.configTheme = function (chart) { + var theme = _super.prototype.configTheme.call(this, chart); + var _a = util_1.parseJson(chart.customAttr), basicStyle = _a.basicStyle, tableCell = _a.tableCell; + if (tableCell.mergeCells) { + var tableFontColor = util_1.hexColorToRGBA(tableCell.tableFontColor, basicStyle.alpha); + var tableItemBgColor = tableCell.tableItemBgColor; + if (!util_1.isAlphaColor(tableItemBgColor)) { + tableItemBgColor = util_1.hexColorToRGBA(tableItemBgColor, basicStyle.alpha); + } + var tableBorderColor = basicStyle.tableBorderColor; + var tableItemAlign = tableCell.tableItemAlign, tableItemFontSize = tableCell.tableItemFontSize; + var fontStyle = tableCell.isItalic ? 'italic' : 'normal'; + var fontWeight = tableCell.isBolder === false ? 'normal' : 'bold'; + var mergeCellTheme = { + dataCell: { + cell: { + crossBackgroundColor: tableItemBgColor + } + }, + mergedCell: { + cell: { + backgroundColor: tableItemBgColor, + crossBackgroundColor: tableItemBgColor, + horizontalBorderColor: tableBorderColor, + verticalBorderColor: tableBorderColor, + horizontalBorderWidth: tableCell.showHorizonBorder ? 1 : 0, + verticalBorderWidth: tableCell.showVerticalBorder ? 1 : 0 + }, + bolderText: { + fill: tableFontColor, + textAlign: tableItemAlign, + fontSize: tableItemFontSize, + fontStyle: fontStyle, + fontWeight: fontWeight + }, + text: { + fill: tableFontColor, + textAlign: tableItemAlign, + fontSize: tableItemFontSize, + fontStyle: fontStyle, + fontWeight: fontWeight + }, + measureText: { + fill: tableFontColor, + textAlign: tableItemAlign, + fontSize: tableItemFontSize, + fontStyle: fontStyle, + fontWeight: fontWeight + }, + seriesText: { + fill: tableFontColor, + textAlign: tableItemAlign, + fontSize: tableItemFontSize, + fontStyle: fontStyle, + fontWeight: fontWeight + } + } + }; + lodash_es_1.merge(theme, mergeCellTheme); + } + return theme; + }; + TableInfo.prototype.configSummaryRowAndIndex = function (chart, pageInfo, s2Options, s2DataConfig) { + var _a, _b; + var _c = util_1.parseJson(chart.customAttr), tableHeader = _c.tableHeader, basicStyle = _c.basicStyle, tableCell = _c.tableCell; + var fields = (_b = (_a = chart.data) === null || _a === void 0 ? void 0 : _a.fields) !== null && _b !== void 0 ? _b : []; + // 开启序号之后,第一列就是序号列,修改 label 即可 + if (s2Options.showSeriesNumber) { + var indexLabel_1 = tableHeader.indexLabel; + if (!indexLabel_1) { + indexLabel_1 = ''; + } + s2Options.layoutCoordinate = function (_, __, col) { + if (col.colIndex === 0 && col.rowIndex === 0) { + col.label = indexLabel_1; + col.value = indexLabel_1; + } + }; + } + var showSummary = basicStyle.showSummary, summaryLabel = basicStyle.summaryLabel; + var data = s2DataConfig.data; + var xAxis = chart.xAxis; + if (showSummary && (data === null || data === void 0 ? void 0 : data.length)) { + // 设置汇总行高度和表头一致 + var heightByField = {}; + heightByField[data.length] = tableHeader.tableTitleHeight; + s2Options.style.rowCfg = { heightByField: heightByField }; + // 计算汇总加入到数据里,冻结最后一行 + s2Options.frozenTrailingRowCount = 1; + var axis = lodash_es_1.filter(xAxis, function (axis) { return [2, 3, 4].includes(axis.deType); }); + var summaryObj = common_table_1.getSummaryRow(data, axis, basicStyle.seriesSummary); + data.push(summaryObj); + } + s2Options.dataCell = function (viewMeta) { + var _a; + // 总计行处理 + if (showSummary && viewMeta.rowIndex === data.length - 1) { + if (viewMeta.colIndex === 0) { + if (tableHeader.showIndex) { + viewMeta.fieldValue = summaryLabel !== null && summaryLabel !== void 0 ? summaryLabel : t('chart.total_show'); + } + else { + // 第一列不是数值类型的,显示总计 + if (![2, 3, 4].includes((_a = xAxis === null || xAxis === void 0 ? void 0 : xAxis[0]) === null || _a === void 0 ? void 0 : _a.deType)) { + viewMeta.fieldValue = summaryLabel !== null && summaryLabel !== void 0 ? summaryLabel : t('chart.total_show'); + } + } + } + return new common_table_1.SummaryCell(viewMeta, viewMeta === null || viewMeta === void 0 ? void 0 : viewMeta.spreadsheet); + } + var field = fields.find(function (f) { return f.gisbiName === viewMeta.valueField; }); + if ((field === null || field === void 0 ? void 0 : field.deType) === 7 && chart.showPosition !== 'dialog') { + return new ImageCell(viewMeta, viewMeta === null || viewMeta === void 0 ? void 0 : viewMeta.spreadsheet); + } + if (viewMeta.colIndex === 0 && s2Options.showSeriesNumber) { + if (tableCell.mergeCells) { + viewMeta.fieldValue = common_table_1.getRowIndex(s2Options.mergedCellsInfo, viewMeta); + } + else { + viewMeta.fieldValue = + pageInfo.pageSize * (pageInfo.currentPage - 1) + viewMeta.rowIndex + 1; + } + } + // 配置文本自动换行参数 + viewMeta.autoWrap = tableCell.mergeCells ? false : basicStyle.autoWrap; + viewMeta.maxLines = basicStyle.maxLines; + return new common_table_1.CustomDataCell(viewMeta, viewMeta === null || viewMeta === void 0 ? void 0 : viewMeta.spreadsheet); + }; + }; + TableInfo.prototype.summaryRowStyle = function (newChart, newData, tableCell, tableHeader, showSummary) { + if (!showSummary || !newData.length) + return; + var columns = newChart.dataCfg.fields.columns; + var showHeader = tableHeader.showTableHeader === true; + // 不显示表头时,减少一个表头的高度 + var headerAndSummaryHeight = showHeader ? getMaxTreeDepth(columns) + 1 : 1; + newChart.on(s2_1.S2Event.LAYOUT_BEFORE_RENDER, function () { + var totalHeight = tableHeader.tableTitleHeight * headerAndSummaryHeight + + tableCell.tableItemHeight * (newData.length - 1); + if (totalHeight < newChart.container.cfg.height) { + newChart.options.height = + totalHeight < newChart.container.cfg.height - 8 ? totalHeight + 8 : totalHeight; + } + }); + }; + return TableInfo; +}(s2_2.S2ChartView)); +exports.TableInfo = TableInfo; +function calcTreeWidth(node) { + var _a; + if (!((_a = node.children) === null || _a === void 0 ? void 0 : _a.length)) { + return node.width; + } + return node.children.reduce(function (pre, cur) { + return pre + calcTreeWidth(cur); + }, 0); +} +function getStartPosition(node) { + var _a; + if (!((_a = node.children) === null || _a === void 0 ? void 0 : _a.length)) { + return node.x; + } + return getStartPosition(node.children[0]); +} +function getMaxTreeDepth(nodes) { + if (!(nodes === null || nodes === void 0 ? void 0 : nodes.length)) { + return 0; + } + return Math.max.apply(Math, nodes.map(function (node) { + var _a; + if (!((_a = node.children) === null || _a === void 0 ? void 0 : _a.length)) { + return 1; + } + return getMaxTreeDepth(node.children) + 1; + })); +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/table/dist/table-normal.js b/frontend/src/data-visualization/chart/components/js/panel/charts/table/dist/table-normal.js new file mode 100644 index 0000000..4555d60 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/table/dist/table-normal.js @@ -0,0 +1,356 @@ +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __spreadArrays = (this && this.__spreadArrays) || function () { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; + for (var r = Array(s), k = 0, i = 0; i < il; i++) + for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) + r[k] = a[j]; + return r; +}; +exports.__esModule = true; +exports.TableNormal = void 0; +var useI18n_1 = require("@/hooks/web/useI18n"); +var formatter_1 = require("@/views/chart/components/js/formatter"); +var common_table_1 = require("@/views/chart/components/js/panel/common/common_table"); +var s2_1 = require("@/views/chart/components/js/panel/types/impl/s2"); +var util_1 = require("@/views/chart/components/js/util"); +var s2_2 = require("@antv/s2"); +var lodash_es_1 = require("lodash-es"); +var common_1 = require("./common"); +var t = useI18n_1.useI18n().t; +/** + * 汇总表 + */ +var TableNormal = /** @class */ (function (_super) { + __extends(TableNormal, _super); + function TableNormal() { + var _this = _super.call(this, 'table-normal', []) || this; + _this.properties = common_1.TABLE_EDITOR_PROPERTY; + _this.propertyInner = __assign(__assign({}, common_1.TABLE_EDITOR_PROPERTY_INNER), { 'table-header-selector': __spreadArrays(common_1.TABLE_EDITOR_PROPERTY_INNER['table-header-selector'], [ + 'tableHeaderSort', + 'showTableHeader' + ]), 'basic-style-selector': __spreadArrays(common_1.TABLE_EDITOR_PROPERTY_INNER['basic-style-selector'], [ + 'tablePageMode', + 'showHoverStyle' + ]), 'table-cell-selector': __spreadArrays(common_1.TABLE_EDITOR_PROPERTY_INNER['table-cell-selector'], [ + 'tableFreeze', + 'tableColumnFreezeHead', + 'tableRowFreezeHead' + ]), 'summary-selector': ['showSummary', 'summaryLabel'] }); + _this.axis = ['xAxis', 'yAxis', 'drill', 'filter']; + _this.axisConfig = { + xAxis: { + name: t('chart.drag_block_table_data_column') + " / " + t('chart.dimension'), + type: 'd' + }, + yAxis: { + name: t('chart.drag_block_table_data_column') + " / " + t('chart.quota'), + type: 'q' + } + }; + return _this; + } + TableNormal.prototype.setupDefaultOptions = function (chart) { + chart.xAxis = []; + return chart; + }; + TableNormal.prototype.drawChart = function (drawOption) { + var _this = this; + var _a, _b; + var container = drawOption.container, chart = drawOption.chart, action = drawOption.action, pageInfo = drawOption.pageInfo, resizeAction = drawOption.resizeAction; + var containerDom = document.getElementById(container); + if (!containerDom) + return; + // fields + var fields = chart.data.fields; + var columns = []; + var meta = []; + if (chart.drill) { + // 下钻过滤字段 + var filterFields_1 = chart.drillFilters.map(function (i) { return i.fieldId; }); + // 下钻入口的字段下标 + var drillFieldId_1 = chart.drillFields[0].id; + var drillFieldIndex = chart.xAxis.findIndex(function (ele) { return ele.id === drillFieldId_1; }); + // 当前下钻字段 + var curDrillFieldId_1 = chart.drillFields[filterFields_1.length].id; + var curDrillField = fields.filter(function (ele) { return ele.id === curDrillFieldId_1; }); + filterFields_1.push(curDrillFieldId_1); + // 移除下钻字段,把当前下钻字段插入到下钻入口位置 + fields = fields.filter(function (ele) { + return !filterFields_1.includes(ele.id); + }); + fields.splice.apply(fields, __spreadArrays([drillFieldIndex, 0], curDrillField)); + } + var axisMap = __spreadArrays(chart.xAxis, chart.yAxis).reduce(function (pre, cur) { + pre[cur.gisbiName] = cur; + return pre; + }, {}); + // add drill list + fields.forEach(function (ele) { + var _a; + var f = axisMap[ele.gisbiName]; + if ((f === null || f === void 0 ? void 0 : f.hide) === true) { + return; + } + columns.push(ele.gisbiName); + meta.push({ + field: ele.gisbiName, + name: (_a = ele.chartShowName) !== null && _a !== void 0 ? _a : ele.name, + formatter: function (value) { + if (!f) { + return value; + } + if (value === null || value === undefined) { + return value; + } + if (![2, 3, 4].includes(f.deType) || !lodash_es_1.isNumber(value)) { + return value; + } + var formatCfg = f.formatterCfg; + if (!formatCfg) { + formatCfg = formatter_1.formatterItem; + } + return formatter_1.valueFormatter(value, formatCfg); + } + }); + }); + // 空值处理 + var newData = this.configEmptyDataStrategy(chart); + // data config + var s2DataConfig = { + fields: { + columns: columns + }, + meta: meta, + data: newData + }; + var _c = util_1.parseJson(chart.customAttr), basicStyle = _c.basicStyle, tableCell = _c.tableCell, tableHeader = _c.tableHeader, tooltip = _c.tooltip; + // options + var s2Options = { + width: containerDom.getBoundingClientRect().width, + height: containerDom.offsetHeight, + showSeriesNumber: tableHeader.showIndex, + conditions: this.configConditions(chart), + tooltip: { + getContainer: function () { return containerDom; }, + renderTooltip: function (sheet) { return new common_table_1.SortTooltip(sheet); } + }, + interaction: { + hoverHighlight: !(basicStyle.showHoverStyle === false), + scrollbarPosition: newData.length + ? s2_2.ScrollbarPositionType.CONTENT + : s2_2.ScrollbarPositionType.CANVAS + } + }; + // 列宽设置 + s2Options.style = this.configStyle(chart, s2DataConfig); + // 行列冻结 + if (tableCell.tableFreeze) { + s2Options.frozenColCount = (_a = tableCell.tableColumnFreezeHead) !== null && _a !== void 0 ? _a : 0; + s2Options.frozenRowCount = (_b = tableCell.tableRowFreezeHead) !== null && _b !== void 0 ? _b : 0; + } + // tooltip + this.configTooltip(chart, s2Options); + // 隐藏表头,保留顶部的分割线, 禁用表头横向 resize + if (tableHeader.showTableHeader === false) { + s2Options.style.colCfg.height = 1; + if (tableCell.showHorizonBorder === false) { + s2Options.style.colCfg.height = 0; + } + s2Options.interaction.resize = { + colCellVertical: false + }; + s2Options.colCell = function (node, sheet, config) { + node.label = ' '; + return new s2_2.TableColCell(node, sheet, config); + }; + } + else { + // header interaction + chart.container = container; + this.configHeaderInteraction(chart, s2Options); + } + // 配置总计和序号列 + this.configSummaryRowAndIndex(chart, pageInfo, s2Options, s2DataConfig); + // 开始渲染 + var newChart = new s2_2.TableSheet(containerDom, s2DataConfig, s2Options); + // 总计紧贴在单元格后面 + this.summaryRowStyle(newChart, newData, tableCell, tableHeader, basicStyle.showSummary); + // 自适应铺满 + if (basicStyle.tableColumnMode === 'adapt') { + newChart.on(s2_2.S2Event.LAYOUT_RESIZE_COL_WIDTH, function () { + newChart.store.set('lastLayoutResult', newChart.facet.layoutResult); + }); + newChart.on(s2_2.S2Event.LAYOUT_AFTER_HEADER_LAYOUT, function (ev) { + var _a, _b; + var lastLayoutResult = newChart.store.get('lastLayoutResult'); + if (lastLayoutResult) { + // 拖动表头 resize + var widthByFieldValue_1 = (_b = (_a = newChart.options.style) === null || _a === void 0 ? void 0 : _a.colCfg) === null || _b === void 0 ? void 0 : _b.widthByFieldValue; + var lastLayoutWidthMap_1 = (lastLayoutResult === null || lastLayoutResult === void 0 ? void 0 : lastLayoutResult.colLeafNodes.reduce(function (p, n) { + var _a; + p[n.value] = (_a = widthByFieldValue_1 === null || widthByFieldValue_1 === void 0 ? void 0 : widthByFieldValue_1[n.value]) !== null && _a !== void 0 ? _a : n.width; + return p; + }, {})) || {}; + var totalWidth_1 = ev.colLeafNodes.reduce(function (p, n) { + n.width = lastLayoutWidthMap_1[n.value] || n.width; + n.x = p; + return p + n.width; + }, 0); + ev.colsHierarchy.width = totalWidth_1; + newChart.store.set('lastLayoutResult', undefined); + return; + } + var containerWidth = containerDom.getBoundingClientRect().width; + var scale = containerWidth / ev.colsHierarchy.width; + if (scale <= 1) { + // 图库计算的布局宽度已经大于等于容器宽度,不需要再扩大,但是需要处理非整数宽度值,不然会出现透明细线 + ev.colLeafNodes.reduce(function (p, n) { + n.width = Math.round(n.width); + n.x = p; + return p + n.width; + }, 0); + return; + } + var totalWidth = ev.colLeafNodes.reduce(function (p, n) { + n.width = Math.round(n.width * scale); + n.x = p; + return p + n.width; + }, 0); + if (totalWidth > containerWidth) { + // 从最后一列减掉 + ev.colLeafNodes[ev.colLeafNodes.length - 1].width -= totalWidth - containerWidth; + } + ev.colsHierarchy.width = containerWidth; + }); + } + common_table_1.configEmptyDataStyle(newChart, basicStyle, newData, container); + // click + newChart.on(s2_2.S2Event.DATA_CELL_CLICK, function (ev) { + var cell = newChart.getCell(ev.target); + var meta = cell.getMeta(); + var nameIdMap = fields.reduce(function (pre, next) { + pre[next['gisbiName']] = next['id']; + return pre; + }, {}); + var rowData = newChart.dataSet.getRowData(meta); + var dimensionList = []; + for (var key in rowData) { + if (nameIdMap[key]) { + dimensionList.push({ id: nameIdMap[key], value: rowData[key] }); + } + } + var param = { + x: ev.x, + y: ev.y, + data: { + dimensionList: dimensionList, + name: nameIdMap[meta.valueField], + sourceType: 'table-normal', + quotaList: [] + } + }; + action(param); + }); + // tooltip + var show = tooltip.show; + if (show) { + newChart.on(s2_2.S2Event.COL_CELL_HOVER, function (event) { return _this.showTooltip(newChart, event, meta); }); + newChart.on(s2_2.S2Event.DATA_CELL_HOVER, function (event) { return _this.showTooltip(newChart, event, meta); }); + // touch + this.configTouchEvent(newChart, drawOption, meta); + } + // header resize + newChart.on(s2_2.S2Event.LAYOUT_RESIZE_COL_WIDTH, function (ev) { return resizeAction(ev); }); + // right click + newChart.on(s2_2.S2Event.GLOBAL_CONTEXT_MENU, function (event) { return common_table_1.copyContent(newChart, event, meta); }); + // theme + var customTheme = this.configTheme(chart); + newChart.setThemeCfg({ theme: customTheme }); + return newChart; + }; + TableNormal.prototype.configSummaryRowAndIndex = function (chart, pageInfo, s2Options, s2DataConfig) { + var _a = util_1.parseJson(chart.customAttr), tableHeader = _a.tableHeader, basicStyle = _a.basicStyle; + // 开启序号之后,第一列就是序号列,修改 label 即可 + if (s2Options.showSeriesNumber) { + var indexLabel_1 = tableHeader.indexLabel; + if (!indexLabel_1) { + indexLabel_1 = ''; + } + s2Options.layoutCoordinate = function (_, __, col) { + if (col.colIndex === 0 && col.rowIndex === 0) { + col.label = indexLabel_1; + col.value = indexLabel_1; + } + }; + } + var showSummary = basicStyle.showSummary, summaryLabel = basicStyle.summaryLabel; + var data = s2DataConfig.data; + var xAxis = chart.xAxis, yAxis = chart.yAxis; + if (showSummary && (data === null || data === void 0 ? void 0 : data.length)) { + // 设置汇总行高度和表头一致 + var heightByField = {}; + heightByField[data.length] = tableHeader.tableTitleHeight; + s2Options.style.rowCfg = { heightByField: heightByField }; + // 计算汇总加入到数据里,冻结最后一行 + s2Options.frozenTrailingRowCount = 1; + var summaryObj = common_table_1.getSummaryRow(data, yAxis, basicStyle.seriesSummary); + data.push(summaryObj); + } + s2Options.dataCell = function (viewMeta) { + // 总计行处理 + if (showSummary && viewMeta.rowIndex === data.length - 1) { + if (viewMeta.colIndex === 0) { + if (tableHeader.showIndex || (xAxis === null || xAxis === void 0 ? void 0 : xAxis.length)) { + viewMeta.fieldValue = summaryLabel !== null && summaryLabel !== void 0 ? summaryLabel : t('chart.total_show'); + } + } + return new common_table_1.SummaryCell(viewMeta, viewMeta === null || viewMeta === void 0 ? void 0 : viewMeta.spreadsheet); + } + if (viewMeta.colIndex === 0 && s2Options.showSeriesNumber) { + viewMeta.fieldValue = pageInfo.pageSize * (pageInfo.currentPage - 1) + viewMeta.rowIndex + 1; + } + return new common_table_1.CustomDataCell(viewMeta, viewMeta === null || viewMeta === void 0 ? void 0 : viewMeta.spreadsheet); + }; + }; + TableNormal.prototype.summaryRowStyle = function (newChart, newData, tableCell, tableHeader, showSummary) { + if (!showSummary || !newData.length) + return; + newChart.on(s2_2.S2Event.LAYOUT_BEFORE_RENDER, function () { + var showHeader = tableHeader.showTableHeader === true; + // 不显示表头时,减少一个表头的高度 + var headerAndSummaryHeight = showHeader ? 2 : 1; + var totalHeight = tableHeader.tableTitleHeight * headerAndSummaryHeight + + tableCell.tableItemHeight * (newData.length - 1); + if (totalHeight < newChart.container.cfg.height) { + newChart.options.height = + totalHeight < newChart.container.cfg.height - 8 ? totalHeight + 8 : totalHeight; + } + }); + }; + return TableNormal; +}(s2_1.S2ChartView)); +exports.TableNormal = TableNormal; diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/table/dist/table-pivot.js b/frontend/src/data-visualization/chart/components/js/panel/charts/table/dist/table-pivot.js new file mode 100644 index 0000000..f8d1899 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/table/dist/table-pivot.js @@ -0,0 +1,1278 @@ +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __spreadArrays = (this && this.__spreadArrays) || function () { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; + for (var r = Array(s), k = 0, i = 0; i < il; i++) + for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) + r[k] = a[j]; + return r; +}; +var _a; +exports.__esModule = true; +exports.setColorOpacity = exports.getDataAvgByField = exports.getDataExtremumByField = exports.getDataSumByField = exports.isNotNumber = exports.TablePivot = void 0; +var s2_1 = require("@antv/s2"); +var formatter_1 = require("../../../formatter"); +var util_1 = require("../../../util"); +var s2_2 = require("../../types/impl/s2"); +var common_1 = require("./common"); +var useI18n_1 = require("@/hooks/web/useI18n"); +var lodash_es_1 = require("lodash-es"); +var common_table_1 = require("../../common/common_table"); +var decimal_js_1 = require("decimal.js"); +var chart_1 = require("@/views/chart/components/editor/util/chart"); +var t = useI18n_1.useI18n().t; +var CustomPivotDataset = /** @class */ (function (_super) { + __extends(CustomPivotDataset, _super); + function CustomPivotDataset() { + return _super !== null && _super.apply(this, arguments) || this; + } + CustomPivotDataset.prototype.getTotalValue = function (query, totalStatus) { + var _a; + var options = this.spreadsheet.options; + var effectiveStatus = lodash_es_1.some(totalStatus); + var status = effectiveStatus ? totalStatus : this.getTotalStatus(query); + var _b = getAggregationAndCalcFuncByQuery(status, options === null || options === void 0 ? void 0 : options.totals) || {}, aggregation = _b.aggregation, calcFunc = _b.calcFunc; + // 聚合方式从用户配置的 s2Options.totals 取, 在触发前端兜底计算汇总逻辑时, 如果没有汇总的配置, 默认按 [求和] 计算,避免排序失效. + var defaultAggregation = lodash_es_1.isEmpty(options === null || options === void 0 ? void 0 : options.totals) && !this.spreadsheet.isHierarchyTreeType() ? s2_1.Aggregation.SUM : ''; + var calcAction = calcActionByType[aggregation || defaultAggregation]; + // 前端计算汇总值 + if (calcAction || calcFunc) { + var data = this.getMultiData(query, { + queryType: s2_1.QueryDataType.DetailOnly + }); + var totalValue = void 0; + if (calcFunc) { + totalValue = calcFunc(query, data, this.spreadsheet, status); + } + else if (calcAction) { + totalValue = calcAction(data, s2_1.VALUE_FIELD); + } + return __assign(__assign({}, query), (_a = {}, _a[s2_1.VALUE_FIELD] = totalValue, _a[query[s2_1.EXTRA_FIELD]] = totalValue, _a)); + } + }; + return CustomPivotDataset; +}(s2_1.PivotDataSet)); +/** + * 透视表 + */ +var TablePivot = /** @class */ (function (_super) { + __extends(TablePivot, _super); + function TablePivot() { + var _this = _super.call(this, 'table-pivot', []) || this; + _this.properties = [ + 'border-style', + 'background-overall-component', + 'basic-style-selector', + 'table-header-selector', + 'table-cell-selector', + 'table-total-selector', + 'title-selector', + 'tooltip-selector', + 'function-cfg', + 'threshold', + 'linkage', + 'jump-set' + ]; + _this.propertyInner = __assign(__assign({}, common_1.TABLE_EDITOR_PROPERTY_INNER), { 'table-header-selector': [ + 'tableHeaderBgColor', + 'tableTitleFontSize', + 'tableHeaderFontColor', + 'tableTitleHeight', + 'tableHeaderAlign', + 'showColTooltip', + 'showRowTooltip', + 'showHorizonBorder', + 'showVerticalBorder', + 'rowHeaderFreeze' + ], 'table-total-selector': ['row', 'col'], 'basic-style-selector': [ + 'tableColumnMode', + 'tableBorderColor', + 'tableScrollBarColor', + 'alpha', + 'tableLayoutMode', + 'showHoverStyle', + 'quotaPosition', + 'quotaColLabel' + ] }); + _this.axis = ['xAxis', 'xAxisExt', 'yAxis', 'filter']; + _this.axisConfig = { + xAxis: { + name: t('chart.table_pivot_row') + " / " + t('chart.dimension'), + type: 'd' + }, + xAxisExt: { + name: t('chart.drag_block_table_data_column') + " / " + t('chart.dimension'), + type: 'd', + allowEmpty: true + }, + yAxis: { + name: t('chart.drag_block_table_data_column') + " / " + t('chart.quota'), + type: 'q' + } + }; + return _this; + } + TablePivot.prototype.drawChart = function (drawOption) { + var _a; + var _this = this; + var _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o; + var container = drawOption.container, chart = drawOption.chart, chartObj = drawOption.chartObj, action = drawOption.action; + var containerDom = document.getElementById(container); + var columnFields = chart.xAxisExt, rowFields = chart.xAxis, valueFields = chart.yAxis; + var _p = [columnFields, rowFields, valueFields].map(function (arr) { + return arr.map(function (i) { return i.gisbiName; }); + }), c = _p[0], r = _p[1], v = _p[2]; + // fields + var _q = chart.data, fields = _q.fields, customCalc = _q.customCalc; + if (!fields || fields.length === 0) { + if (chartObj) { + chartObj.destroy(); + } + return; + } + var columns = []; + var meta = []; + var valueFieldMap = __spreadArrays(chart.xAxis, chart.xAxisExt, chart.yAxis).reduce(function (p, n) { + p[n.gisbiName] = n; + return p; + }, {}); + fields.forEach(function (ele) { + var _a; + var f = valueFieldMap[ele.gisbiName]; + columns.push(ele.gisbiName); + meta.push({ + field: ele.gisbiName, + name: (_a = ele.chartShowName) !== null && _a !== void 0 ? _a : ele.name, + formatter: function (value) { + if (!f) { + return value; + } + if (value === null || value === undefined) { + return value; + } + if (![2, 3, 4].includes(f.deType) || !lodash_es_1.isNumber(value)) { + return value; + } + if (f.formatterCfg) { + return formatter_1.valueFormatter(value, f.formatterCfg); + } + else { + return formatter_1.valueFormatter(value, formatter_1.formatterItem); + } + } + }); + }); + // total config + var _r = util_1.parseJson(chart.customAttr), basicStyle = _r.basicStyle, tooltip = _r.tooltip, tableTotal = _r.tableTotal, tableHeader = _r.tableHeader; + if (!tableTotal.row.subTotalsDimensionsNew || tableTotal.row.subTotalsDimensions == undefined) { + tableTotal.row.subTotalsDimensions = r; + } + tableTotal.col.subTotalsDimensions = c; + // 解析合计、小计排序 + var sortParams = []; + var rowTotalSort = false; + if (tableTotal.row.totalSort && + tableTotal.row.totalSort !== 'none' && + c.length > 0 && + tableTotal.row.showGrandTotals && + v.indexOf(tableTotal.row.totalSortField) > -1) { + c.forEach(function (i) { + var _a; + var sort = { + sortFieldId: i, + sortMethod: tableTotal.row.totalSort.toUpperCase(), + sortByMeasure: s2_1.TOTAL_VALUE, + query: (_a = {}, + _a[s2_1.EXTRA_FIELD] = tableTotal.row.totalSortField, + _a) + }; + sortParams.push(sort); + }); + rowTotalSort = true; + } + var colTotalSort = false; + if (tableTotal.col.totalSort && + tableTotal.col.totalSort !== 'none' && + r.length > 0 && + tableTotal.col.showGrandTotals && + v.indexOf(tableTotal.col.totalSortField) > -1) { + r.forEach(function (i) { + var _a; + var sort = { + sortFieldId: i, + sortMethod: tableTotal.col.totalSort.toUpperCase(), + sortByMeasure: s2_1.TOTAL_VALUE, + query: (_a = {}, + _a[s2_1.EXTRA_FIELD] = tableTotal.col.totalSortField, + _a) + }; + sortParams.push(sort); + }); + colTotalSort = true; + } + //列维度为空,行排序按照指标列来排序,取第一个有排序设置的指标 + if (!(columnFields === null || columnFields === void 0 ? void 0 : columnFields.length)) { + var sortField = valueFields === null || valueFields === void 0 ? void 0 : valueFields.find(function (v) { return !['none', 'custom_sort'].includes(v.sort); }); + if (sortField) { + var sort = { + sortFieldId: r[0], + sortMethod: sortField.sort.toUpperCase(), + sortByMeasure: s2_1.TOTAL_VALUE, + query: (_a = {}, + _a[s2_1.EXTRA_FIELD] = sortField.gisbiName, + _a) + }; + sortParams.push(sort); + } + } + // 自定义总计小计 + var totals = [ + tableTotal.row.calcTotals, + tableTotal.row.calcSubTotals, + tableTotal.col.calcTotals, + tableTotal.col.calcSubTotals + ]; + var axisMap = { + row: chart.xAxis, + col: chart.xAxisExt, + quota: chart.yAxis + }; + // 沒有列维度需要特殊处理 + if (!((_b = chart.xAxisExt) === null || _b === void 0 ? void 0 : _b.length)) { + //树形模式下,列维度为空,行小计的配置会变成列总计 + if (basicStyle.tableLayoutMode === 'tree') { + tableTotal.col.calcTotals = tableTotal.row.calcSubTotals; + if (!((_c = tableTotal.col.calcTotals.cfg) === null || _c === void 0 ? void 0 : _c.length)) { + tableTotal.col.calcTotals.cfg = chart.yAxis.map(function (y) { + return { + gisbiName: y.gisbiName, + aggregation: 'SUM' + }; + }); + } + } + else { + // 列总计设置为空 + tableTotal.col.calcTotals.calcFunc = function () { return '-'; }; + } + } + totals.forEach(function (total) { + var _a; + if ((_a = total.cfg) === null || _a === void 0 ? void 0 : _a.length) { + delete total.aggregation; + var totalCfgMap_1 = total.cfg.reduce(function (p, n) { + p[n.gisbiName] = n; + return p; + }, {}); + total.calcFunc = function (query, data, _, status) { + return customCalcFunc(query, data, status, chart, totalCfgMap_1, axisMap, customCalc); + }; + } + }); + // 空值处理 + var newData = this.configEmptyDataStrategy(chart); + // 行列维度排序 + if (!rowTotalSort) { + c === null || c === void 0 ? void 0 : c.forEach(function (f, i) { + var _a, _b, _c; + if (((_a = valueFieldMap[f]) === null || _a === void 0 ? void 0 : _a.sort) === 'none') { + return; + } + var sort = { + sortFieldId: f + }; + var sortMethod = (_c = (_b = valueFieldMap[f]) === null || _b === void 0 ? void 0 : _b.sort) === null || _c === void 0 ? void 0 : _c.toUpperCase(); + if (sortMethod === 'CUSTOM_SORT') { + sort.sortBy = valueFieldMap[f].customSort; + } + else { + if (i === 0) { + sort.sortMethod = sortMethod; + } + else { + var fieldValues = newData.map(function (item) { return item[f]; }); + var uniqueValues = __spreadArrays(new Set(fieldValues)); + // 根据配置动态决定排序顺序 + uniqueValues.sort(function (a, b) { + var _a; + if ([2, 3, 4].includes((_a = valueFieldMap[f]) === null || _a === void 0 ? void 0 : _a.deType)) { + return sortMethod === 'ASC' ? a - b : b - a; + } + if (!a && !b) { + return 0; + } + if (!a) { + return sortMethod === 'ASC' ? -1 : 1; + } + if (!b) { + return sortMethod === 'ASC' ? 1 : -1; + } + return sortMethod === 'ASC' ? a.localeCompare(b) : b.localeCompare(a); + }); + sort.sortBy = uniqueValues; + } + } + sortParams.push(sort); + }); + } + if (!colTotalSort) { + r === null || r === void 0 ? void 0 : r.forEach(function (f, i) { + var _a, _b, _c; + if (((_a = valueFieldMap[f]) === null || _a === void 0 ? void 0 : _a.sort) === 'none') { + return; + } + var sort = { + sortFieldId: f + }; + var sortMethod = (_c = (_b = valueFieldMap[f]) === null || _b === void 0 ? void 0 : _b.sort) === null || _c === void 0 ? void 0 : _c.toUpperCase(); + if (sortMethod === 'CUSTOM_SORT') { + sort.sortBy = valueFieldMap[f].customSort; + } + else { + if (i === 0) { + sort.sortMethod = sortMethod; + } + else { + var fieldValues = newData.map(function (item) { return item[f]; }); + var uniqueValues = __spreadArrays(new Set(fieldValues)); + // 根据配置动态决定排序顺序 + uniqueValues.sort(function (a, b) { + var _a; + if ([2, 3, 4].includes((_a = valueFieldMap[f]) === null || _a === void 0 ? void 0 : _a.deType)) { + return sortMethod === 'ASC' ? a - b : b - a; + } + if (!a && !b) { + return 0; + } + if (!a) { + return sortMethod === 'ASC' ? -1 : 1; + } + if (!b) { + return sortMethod === 'ASC' ? 1 : -1; + } + return sortMethod === 'ASC' ? a.localeCompare(b) : b.localeCompare(a); + }); + sort.sortBy = uniqueValues; + } + } + sortParams.push(sort); + }); + } + // data config + var s2DataConfig = { + fields: { + rows: r, + columns: c, + values: v, + valueInCols: !(basicStyle.quotaPosition === 'row') + }, + meta: meta, + data: newData, + sortParams: sortParams + }; + var s2Options = { + width: containerDom.offsetWidth, + height: containerDom.offsetHeight, + totals: tableTotal, + cornerExtraFieldText: (_d = basicStyle.quotaColLabel) !== null && _d !== void 0 ? _d : t('dataset.value'), + conditions: this.configConditions(chart), + tooltip: { + getContainer: function () { return containerDom; } + }, + hierarchyType: (_e = basicStyle.tableLayoutMode) !== null && _e !== void 0 ? _e : 'grid', + dataSet: function (spreadSheet) { return new CustomPivotDataset(spreadSheet); }, + interaction: { + hoverHighlight: !(basicStyle.showHoverStyle === false) + }, + dataCell: function (meta) { + return new common_table_1.CustomDataCell(meta, meta.spreadsheet); + }, + frozenRowHeader: !(tableHeader.rowHeaderFreeze === false) + }; + // options + s2Options.style = this.configStyle(chart, s2DataConfig); + // 默认展开层级 + if (basicStyle.tableLayoutMode === 'tree') { + var defaultExpandLevel = basicStyle.defaultExpandLevel; + if (lodash_es_1.isNumber(defaultExpandLevel)) { + if (defaultExpandLevel >= chart.xAxis.length) { + s2Options.style.rowExpandDepth = defaultExpandLevel; + } + else { + s2Options.style.rowExpandDepth = defaultExpandLevel - 2; + } + } + if (defaultExpandLevel === 'all') { + s2Options.style.rowExpandDepth = chart.xAxis.length; + } + if (!defaultExpandLevel) { + s2Options.style.hierarchyCollapse = true; + } + } + // 列汇总别名 + if (!(basicStyle.quotaPosition === 'row' && basicStyle.tableLayoutMode === 'tree')) { + if (basicStyle.quotaPosition !== 'row' && ((_f = chart.xAxisExt) === null || _f === void 0 ? void 0 : _f.length) && + ((_g = chart.yAxis) === null || _g === void 0 ? void 0 : _g.length) > 1 && + tableTotal.col.showGrandTotals && ((_j = (_h = tableTotal.col.calcTotals) === null || _h === void 0 ? void 0 : _h.cfg) === null || _j === void 0 ? void 0 : _j.length)) { + var colTotalCfgMap_1 = tableTotal.col.calcTotals.cfg.reduce(function (p, n) { + p[n.gisbiName] = n; + return p; + }, {}); + s2Options.layoutCoordinate = function (_, __, col) { + var _a; + if (col === null || col === void 0 ? void 0 : col.isGrandTotals) { + if ((_a = colTotalCfgMap_1[col.value]) === null || _a === void 0 ? void 0 : _a.label) { + col.label = colTotalCfgMap_1[col.value].label; + } + } + }; + } + if (basicStyle.quotaPosition === 'row' && ((_k = chart.xAxisExt) === null || _k === void 0 ? void 0 : _k.length) && + ((_l = chart.yAxis) === null || _l === void 0 ? void 0 : _l.length) > 1 && + tableTotal.row.showGrandTotals && ((_o = (_m = tableTotal.row.calcTotals) === null || _m === void 0 ? void 0 : _m.cfg) === null || _o === void 0 ? void 0 : _o.length)) { + var rowTotalCfgMap_1 = tableTotal.row.calcTotals.cfg.reduce(function (p, n) { + p[n.gisbiName] = n; + return p; + }, {}); + // eslint-disable-next-line + s2Options.layoutCoordinate = function (_, row, __) { + var _a; + if (row === null || row === void 0 ? void 0 : row.isGrandTotals) { + if ((_a = rowTotalCfgMap_1[row.value]) === null || _a === void 0 ? void 0 : _a.label) { + row.label = rowTotalCfgMap_1[row.value].label; + } + } + }; + } + } + // tooltip + this.configTooltip(chart, s2Options); + // 开始渲染 + var s2 = new s2_1.PivotSheet(containerDom, s2DataConfig, s2Options); + // 自适应铺满 + if (basicStyle.tableColumnMode === 'adapt') { + s2.on(s2_1.S2Event.LAYOUT_RESIZE_COL_WIDTH, function () { + s2.store.set('lastLayoutResult', s2.facet.layoutResult); + }); + // 平铺模式行头resize + s2.on(s2_1.S2Event.LAYOUT_RESIZE_ROW_WIDTH, function () { + s2.store.set('lastLayoutResult', s2.facet.layoutResult); + }); + // 树形模式行头resize + s2.on(s2_1.S2Event.LAYOUT_RESIZE_TREE_WIDTH, function () { + s2.store.set('lastLayoutResult', s2.facet.layoutResult); + }); + s2.on(s2_1.S2Event.LAYOUT_AFTER_HEADER_LAYOUT, function (ev) { + var _a, _b, _c, _d, _e; + var lastLayoutResult = s2.store.get('lastLayoutResult'); + if (lastLayoutResult) { + // 拖动 col 表头 resize + var colWidthByFieldValue_1 = (_b = (_a = s2.options.style) === null || _a === void 0 ? void 0 : _a.colCfg) === null || _b === void 0 ? void 0 : _b.widthByFieldValue; + // 平铺模式拖动 row 表头 resize + var rowWidthByField_1 = (_d = (_c = s2.options.style) === null || _c === void 0 ? void 0 : _c.rowCfg) === null || _d === void 0 ? void 0 : _d.widthByField; + // 树形模式拖动 row 表头 resize + var treeRowWidth_1 = ((_e = s2.options.style) === null || _e === void 0 ? void 0 : _e.treeRowsWidth) || lastLayoutResult.rowsHierarchy.width; + var colWidthMap_1 = lastLayoutResult.colLeafNodes.reduce(function (p, n) { + var _a; + p[n.id] = (_a = colWidthByFieldValue_1 === null || colWidthByFieldValue_1 === void 0 ? void 0 : colWidthByFieldValue_1[n.value]) !== null && _a !== void 0 ? _a : n.width; + return p; + }, {}) || {}; + var totalColWidth_1 = ev.colLeafNodes.reduce(function (p, n) { + n.width = colWidthMap_1[n.id] || n.width; + n.x = p; + return p + n.width; + }, 0); + ev.colNodes.forEach(function (n) { + if (n.isLeaf) { + return; + } + n.width = _this.getColWidth(n); + n.x = _this.getLeftChild(n).x; + }); + if (basicStyle.tableLayoutMode === 'tree') { + ev.rowNodes.forEach(function (n) { + n.width = treeRowWidth_1; + }); + ev.rowsHierarchy.width = treeRowWidth_1; + ev.colsHierarchy.width = totalColWidth_1; + } + else { + var rowWidthMap_1 = lastLayoutResult.rowNodes.reduce(function (p, n) { + var _a; + p[n.id] = (_a = rowWidthByField_1 === null || rowWidthByField_1 === void 0 ? void 0 : rowWidthByField_1[n.field]) !== null && _a !== void 0 ? _a : n.width; + return p; + }, {}) || {}; + ev.rowNodes.forEach(function (n) { + n.x = 0; + n.width = rowWidthMap_1[n.id] || n.width; + var tmp = n; + while (tmp.parent.id !== 'root') { + n.x += tmp.parent.width; + tmp = tmp.parent; + } + }); + var totlaRowWidth = ev.rowsHierarchy.sampleNodesForAllLevels.reduce(function (p, n) { + return p + n.width; + }, 0); + var maxRowLevel_1 = ev.rowsHierarchy.maxLevel; + ev.rowNodes.forEach(function (n) { + // 总计和中间层级的小计需要重新计算宽度 + if (n.isTotalRoot || (n.isSubTotals && n.level < maxRowLevel_1)) { + var width = 0; + for (var i = n.level; i <= maxRowLevel_1; i++) { + width += ev.rowsHierarchy.sampleNodesForAllLevels[i].width; + } + n.width = width; + } + }); + ev.rowsHierarchy.width = totlaRowWidth; + ev.colsHierarchy.width = totalColWidth_1; + } + s2.store.set('lastLayoutResult', undefined); + return; + } + var containerWidth = containerDom.getBoundingClientRect().width; + var scale = containerWidth / (ev.colsHierarchy.width + ev.rowsHierarchy.width); + if (scale <= 1) { + return; + } + var totalRowWidth = Math.round(ev.rowsHierarchy.width * scale); + ev.rowNodes.forEach(function (n) { + n.width = Math.round(n.width * scale); + }); + if (basicStyle.tableLayoutMode !== 'tree') { + ev.rowNodes.forEach(function (n) { + n.x = 0; + var tmp = n; + while (tmp.parent.id !== 'root') { + n.x += tmp.parent.width; + tmp = tmp.parent; + } + }); + } + var totalColWidth = ev.colLeafNodes.reduce(function (p, n) { + n.width = Math.round(n.width * scale); + n.x = p; + return p + n.width; + }, 0); + ev.colNodes.forEach(function (n) { + if (n.isLeaf) { + return; + } + n.width = _this.getColWidth(n); + n.x = _this.getLeftChild(n).x; + }); + var totalWidth = totalColWidth + totalRowWidth; + if (totalWidth > containerWidth) { + // 从最后一列减掉 + ev.colLeafNodes[ev.colLeafNodes.length - 1].width -= totalWidth - containerWidth; + totalColWidth = totalColWidth - (totalWidth - containerWidth); + } + ev.colsHierarchy.width = totalColWidth; + ev.rowsHierarchy.width = totalRowWidth; + }); + } + // tooltip + var show = tooltip.show; + if (show) { + s2.on(s2_1.S2Event.COL_CELL_HOVER, function (event) { return _this.showTooltip(s2, event, meta); }); + s2.on(s2_1.S2Event.ROW_CELL_HOVER, function (event) { return _this.showTooltip(s2, event, meta); }); + s2.on(s2_1.S2Event.DATA_CELL_HOVER, function (event) { return _this.showTooltip(s2, event, meta); }); + // touch + this.configTouchEvent(s2, drawOption, meta); + } + // empty data tip + configEmptyDataStyle(s2, newData); + // click + s2.on(s2_1.S2Event.DATA_CELL_CLICK, function (ev) { return _this.dataCellClickAction(chart, ev, s2, action); }); + s2.on(s2_1.S2Event.ROW_CELL_CLICK, function (ev) { return _this.headerCellClickAction(chart, ev, s2, action); }); + s2.on(s2_1.S2Event.COL_CELL_CLICK, function (ev) { return _this.headerCellClickAction(chart, ev, s2, action); }); + // right click + s2.on(s2_1.S2Event.GLOBAL_CONTEXT_MENU, function (event) { return common_table_1.copyContent(s2, event, meta); }); + // theme + var customTheme = this.configTheme(chart); + s2.setThemeCfg({ theme: customTheme }); + return s2; + }; + TablePivot.prototype.getColWidth = function (node) { + var _this = this; + var _a; + var width = 0; + if ((_a = node.children) === null || _a === void 0 ? void 0 : _a.length) { + node.children.forEach(function (child) { + width += _this.getColWidth(child); + }); + } + else { + width = node.width; + } + return width; + }; + TablePivot.prototype.getLeftChild = function (node) { + var _a; + if (!((_a = node.children) === null || _a === void 0 ? void 0 : _a.length)) { + return node; + } + return this.getLeftChild(node.children[0]); + }; + TablePivot.prototype.dataCellClickAction = function (chart, ev, s2Instance, callback) { + var cell = s2Instance.getCell(ev.target); + var meta = cell.getMeta(); + var nameIdMap = chart.data.fields.reduce(function (pre, next) { + pre[next['gisbiName']] = next['id']; + return pre; + }, {}); + var rowData = __assign(__assign({}, meta.rowQuery), meta.colQuery); + rowData[meta.valueField] = meta.fieldValue; + var dimensionList = []; + for (var key in rowData) { + if (nameIdMap[key]) { + dimensionList.push({ id: nameIdMap[key], value: rowData[key] }); + } + } + var param = { + x: ev.x, + y: ev.y, + data: { + dimensionList: dimensionList, + name: nameIdMap[meta.valueField], + sourceType: 'table-pivot', + quotaList: [] + } + }; + callback(param); + }; + TablePivot.prototype.headerCellClickAction = function (chart, ev, s2Instance, callback) { + var cell = s2Instance.getCell(ev.target); + var meta = cell.getMeta(); + var rowData = meta.query; + var nameIdMap = chart.data.fields.reduce(function (pre, next) { + pre[next['gisbiName']] = next['id']; + return pre; + }, {}); + var dimensionList = []; + for (var key in rowData) { + if (nameIdMap[key]) { + dimensionList.push({ id: nameIdMap[key], value: rowData[key] }); + } + } + var param = { + x: ev.x, + y: ev.y, + data: { + dimensionList: dimensionList, + name: nameIdMap[meta.valueField], + sourceType: 'table-pivot', + quotaList: [] + } + }; + callback(param); + }; + TablePivot.prototype.configTheme = function (chart) { + var _a, _b; + var theme = _super.prototype.configTheme.call(this, chart); + var _c = util_1.parseJson(chart.customAttr), basicStyle = _c.basicStyle, tableHeader = _c.tableHeader; + var tableHeaderBgColor = tableHeader.tableHeaderBgColor; + if (!util_1.isAlphaColor(tableHeaderBgColor)) { + tableHeaderBgColor = util_1.hexColorToRGBA(tableHeaderBgColor, basicStyle.alpha); + } + var tableHeaderCornerBgColor = (_a = tableHeader.tableHeaderCornerBgColor) !== null && _a !== void 0 ? _a : chart_1.DEFAULT_TABLE_HEADER.tableHeaderCornerBgColor; + if (!util_1.isAlphaColor(tableHeaderCornerBgColor)) { + tableHeaderCornerBgColor = util_1.hexColorToRGBA(tableHeaderCornerBgColor, basicStyle.alpha); + } + var tableHeaderColBgColor = (_b = tableHeader.tableHeaderColBgColor) !== null && _b !== void 0 ? _b : chart_1.DEFAULT_TABLE_HEADER.tableHeaderColBgColor; + if (!util_1.isAlphaColor(tableHeaderColBgColor)) { + tableHeaderColBgColor = util_1.hexColorToRGBA(tableHeaderColBgColor, basicStyle.alpha); + } + var tableBorderColor = basicStyle.tableBorderColor; + if (!util_1.isAlphaColor(tableBorderColor)) { + tableBorderColor = util_1.hexColorToRGBA(tableBorderColor, basicStyle.alpha); + } + var tableHeaderColFontColor = util_1.hexColorToRGBA(tableHeader.tableHeaderColFontColor, basicStyle.alpha); + var tableHeaderCornerFontColor = util_1.hexColorToRGBA(tableHeader.tableHeaderCornerFontColor, basicStyle.alpha); + var colFontStyle = tableHeader.isColItalic ? 'italic' : 'normal'; + var cornerFontStyle = tableHeader.isCornerItalic ? 'italic' : 'normal'; + var colFontWeight = tableHeader.isColBolder === false ? 'normal' : 'bold'; + var cornerFontWeight = tableHeader.isCornerBolder === false ? 'normal' : 'bold'; + var pivotTheme = { + rowCell: { + cell: { + backgroundColor: tableHeaderColBgColor, + horizontalBorderColor: tableBorderColor, + verticalBorderColor: tableBorderColor + }, + text: { + fill: tableHeaderColFontColor, + fontSize: tableHeader.tableTitleColFontSize, + textAlign: tableHeader.tableHeaderColAlign, + textBaseline: 'top', + fontStyle: colFontStyle, + fontWeight: colFontWeight + }, + bolderText: { + fill: tableHeaderColFontColor, + fontSize: tableHeader.tableTitleColFontSize, + textAlign: tableHeader.tableHeaderColAlign, + fontStyle: colFontStyle, + fontWeight: colFontWeight + }, + measureText: { + fill: tableHeaderColFontColor, + fontSize: tableHeader.tableTitleColFontSize, + textAlign: tableHeader.tableHeaderColAlign, + fontStyle: colFontStyle, + fontWeight: colFontWeight + }, + seriesText: { + fill: tableHeaderColFontColor, + fontSize: tableHeader.tableTitleColFontSize, + textAlign: tableHeader.tableHeaderColAlign, + fontStyle: colFontStyle, + fontWeight: colFontWeight + } + }, + cornerCell: { + cell: { + backgroundColor: tableHeaderCornerBgColor + }, + text: { + fill: tableHeaderCornerFontColor, + fontSize: tableHeader.tableTitleCornerFontSize, + textAlign: tableHeader.tableHeaderCornerAlign, + fontStyle: cornerFontStyle, + fontWeight: cornerFontWeight + }, + bolderText: { + fill: tableHeaderCornerFontColor, + fontSize: tableHeader.tableTitleCornerFontSize, + textAlign: tableHeader.tableHeaderCornerAlign, + fontStyle: cornerFontStyle, + fontWeight: cornerFontWeight + }, + measureText: { + fill: tableHeaderCornerFontColor, + fontSize: tableHeader.tableTitleCornerFontSize, + textAlign: tableHeader.tableHeaderCornerAlign, + fontStyle: cornerFontStyle, + fontWeight: cornerFontWeight + } + } + }; + lodash_es_1.merge(theme, pivotTheme); + if (tableHeader.showHorizonBorder === false) { + var tmp = { + cornerCell: { + cell: { + horizontalBorderColor: tableHeaderBgColor, + horizontalBorderWidth: 0 + } + }, + rowCell: { + cell: { + horizontalBorderColor: tableHeaderBgColor, + horizontalBorderWidth: 0 + } + } + }; + lodash_es_1.merge(theme, tmp); + } + if (tableHeader.showVerticalBorder === false) { + var tmp = { + cornerCell: { + cell: { + verticalBorderColor: tableHeaderBgColor, + verticalBorderWidth: 0 + } + }, + rowCell: { + cell: { + verticalBorderColor: tableHeaderBgColor, + verticalBorderWidth: 0 + } + } + }; + lodash_es_1.merge(theme, tmp); + } + return theme; + }; + TablePivot.prototype.setupDefaultOptions = function (chart) { + var customAttr = chart.customAttr; + if (customAttr.basicStyle.tableColumnMode === 'field') { + customAttr.basicStyle.tableColumnMode = 'custom'; + } + return chart; + }; + return TablePivot; +}(s2_2.S2ChartView)); +exports.TablePivot = TablePivot; +function customCalcFunc(query, data, status, chart, totalCfgMap, axisMap, customCalc) { + var _a; + if (!(data === null || data === void 0 ? void 0 : data.length) || !query[s2_1.EXTRA_FIELD]) { + return '-'; + } + var aggregation = ((_a = totalCfgMap[query[s2_1.EXTRA_FIELD]]) === null || _a === void 0 ? void 0 : _a.aggregation) || 'SUM'; + switch (aggregation) { + case 'SUM': { + return data.reduce(function (p, n) { + var _a; + return p + parseFloat((_a = n[query[s2_1.EXTRA_FIELD]]) !== null && _a !== void 0 ? _a : 0); + }, 0); + } + case 'AVG': { + var sum = data.reduce(function (p, n) { + var _a; + return p + parseFloat((_a = n[query[s2_1.EXTRA_FIELD]]) !== null && _a !== void 0 ? _a : 0); + }, 0); + return sum / data.length; + } + case 'MIN': { + var result = lodash_es_1.minBy(data, function (n) { + return parseFloat(n[query[s2_1.EXTRA_FIELD]]); + }); + return result === null || result === void 0 ? void 0 : result[query[s2_1.EXTRA_FIELD]]; + } + case 'MAX': { + var result = lodash_es_1.maxBy(data, function (n) { + return parseFloat(n[query[s2_1.EXTRA_FIELD]]); + }); + return result === null || result === void 0 ? void 0 : result[query[s2_1.EXTRA_FIELD]]; + } + case 'NONE': { + return '-'; + } + case 'CUSTOM': { + var val = getCustomCalcResult(query, axisMap, chart, status, customCalc || {}); + if (val === '' || val === undefined) { + return '-'; + } + return parseFloat(val); + } + default: { + return data.reduce(function (p, n) { + var _a; + return p + parseFloat((_a = n[query[s2_1.EXTRA_FIELD]]) !== null && _a !== void 0 ? _a : 0); + }, 0); + } + } +} +function getTreeCustomCalcResult(query, axisMap, status, customCalc) { + var _a, _b, _c, _d, _e, _f, _g, _h, _j; + var quotaField = query[s2_1.EXTRA_FIELD]; + var row = axisMap.row, col = axisMap.col; + // 行列交叉总计 + if (status.isRowTotal && status.isColTotal) { + return (_b = (_a = customCalc.rowColTotal) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b[quotaField]; + } + // 列总计 + if (status.isColTotal && !status.isRowSubTotal) { + var colTotal = customCalc.colTotal, rowSubInColTotal = customCalc.rowSubInColTotal; + var path = getTreePath(query, row); + var val = void 0; + if (path.length) { + var subLevel = getSubLevel(query, row); + if (subLevel + 1 === row.length && colTotal) { + path.push(quotaField); + val = lodash_es_1.get(colTotal.data, path); + } + if (subLevel + 1 < row.length && rowSubInColTotal) { + var data = (_c = rowSubInColTotal === null || rowSubInColTotal === void 0 ? void 0 : rowSubInColTotal[subLevel]) === null || _c === void 0 ? void 0 : _c.data; + path.push(quotaField); + val = lodash_es_1.get(data, path); + } + } + return val; + } + // 列小计 + if (status.isColSubTotal && !status.isRowTotal && !status.isRowSubTotal) { + var colSubTotal = customCalc.colSubTotal; + var subColLevel = getSubLevel(query, col); + var subRowLevel = getSubLevel(query, row); + var rowPath = getTreePath(query, row); + var colPath = getTreePath(query, col); + var path = __spreadArrays(rowPath, colPath); + var data = (_d = colSubTotal === null || colSubTotal === void 0 ? void 0 : colSubTotal[subColLevel]) === null || _d === void 0 ? void 0 : _d.data; + // 列小计里面的行小计 + if (rowPath.length < row.length) { + var rowSubInColSub = customCalc.rowSubInColSub; + data = (_f = (_e = rowSubInColSub === null || rowSubInColSub === void 0 ? void 0 : rowSubInColSub[subRowLevel]) === null || _e === void 0 ? void 0 : _e[subColLevel]) === null || _f === void 0 ? void 0 : _f.data; + } + var val = void 0; + if (path.length && data) { + path.push(quotaField); + val = lodash_es_1.get(data, path); + } + return val; + } + // 行总计 + if (status.isRowTotal && !status.isColSubTotal) { + var rowTotal = customCalc.rowTotal; + var path = getTreePath(query, col); + var val = void 0; + if (rowTotal) { + if (path.length) { + path.push(quotaField); + val = lodash_es_1.get(rowTotal.data, path); + } + // 列维度为空,行维度不为空 + if (!col.length && row.length) { + val = lodash_es_1.get(rowTotal.data, quotaField); + } + } + return val; + } + // 行小计 + if (status.isRowSubTotal) { + // 列维度为空,行小计直接当成列总计 + if ((!status.isColTotal && !status.isColSubTotal) || + (!col.length && status.isColTotal && status.isRowSubTotal)) { + var rowSubTotal = customCalc.rowSubTotal; + var rowLevel = getSubLevel(query, row); + var colPath = getTreePath(query, col); + var rowPath = getTreePath(query, row); + var path = __spreadArrays(colPath, rowPath); + var data = (_g = rowSubTotal === null || rowSubTotal === void 0 ? void 0 : rowSubTotal[rowLevel]) === null || _g === void 0 ? void 0 : _g.data; + var val = void 0; + if (path.length && rowSubTotal) { + path.push(quotaField); + val = lodash_es_1.get(data, path); + } + return val; + } + } + // 行总计里面的列小计 + if (status.isRowTotal && status.isColSubTotal) { + var colSubInRowTotal = customCalc.colSubInRowTotal; + var colLevel = getSubLevel(query, col); + var data = (_h = colSubInRowTotal === null || colSubInRowTotal === void 0 ? void 0 : colSubInRowTotal[colLevel]) === null || _h === void 0 ? void 0 : _h.data; + var colPath = getTreePath(query, col); + var val = void 0; + if (colPath.length && colSubInRowTotal) { + colPath.push(quotaField); + val = lodash_es_1.get(data, colPath); + } + return val; + } + // 列总计里面的行小计 + if (status.isColTotal && status.isRowSubTotal) { + var rowSubInColTotal = customCalc.rowSubInColTotal; + var rowSubLevel = getSubLevel(query, row); + var data = (_j = rowSubInColTotal === null || rowSubInColTotal === void 0 ? void 0 : rowSubInColTotal[rowSubLevel]) === null || _j === void 0 ? void 0 : _j.data; + var path = getTreePath(query, row); + var val = void 0; + if (path.length && rowSubInColTotal) { + path.push(quotaField); + val = lodash_es_1.get(data, path); + } + return val; + } + return '-'; +} +function getGridCustomCalcResult(query, axisMap, status, customCalc) { + var _a, _b, _c, _d, _e, _f, _g, _h; + var quotaField = query[s2_1.EXTRA_FIELD]; + var row = axisMap.row, col = axisMap.col; + // 行列交叉总计 + if (status.isRowTotal && status.isColTotal) { + return (_b = (_a = customCalc.rowColTotal) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b[quotaField]; + } + // 列总计 + if (status.isColTotal && !status.isRowSubTotal) { + var colTotal = customCalc.colTotal; + var path = getTreePath(query, row); + var val = void 0; + if (path.length) { + if (colTotal) { + path.push(quotaField); + val = lodash_es_1.get(colTotal.data, path); + } + } + return val; + } + // 列小计 + if (status.isColSubTotal && !status.isRowTotal && !status.isRowSubTotal) { + var colSubTotal = customCalc.colSubTotal; + var subLevel = getSubLevel(query, col); + var rowPath = getTreePath(query, row); + var colPath = getTreePath(query, col); + var path = __spreadArrays(rowPath, colPath); + var data = (_c = colSubTotal === null || colSubTotal === void 0 ? void 0 : colSubTotal[subLevel]) === null || _c === void 0 ? void 0 : _c.data; + var val = void 0; + if (path.length && data) { + path.push(quotaField); + val = lodash_es_1.get(data, path); + } + return val; + } + // 行总计 + if (status.isRowTotal && !status.isColSubTotal) { + var rowTotal = customCalc.rowTotal; + var path = getTreePath(query, col); + var val = void 0; + if (rowTotal) { + if (path.length) { + path.push(quotaField); + val = lodash_es_1.get(rowTotal.data, path); + } + // 列维度为空,行维度不为空 + if (!col.length && row.length) { + val = lodash_es_1.get(rowTotal.data, quotaField); + } + } + return val; + } + // 行小计 + if (status.isRowSubTotal && !status.isColTotal && !status.isColSubTotal) { + var rowSubTotal = customCalc.rowSubTotal; + var rowLevel = getSubLevel(query, row); + var colPath = getTreePath(query, col); + var rowPath = getTreePath(query, row); + var path = __spreadArrays(colPath, rowPath); + var data = (_d = rowSubTotal === null || rowSubTotal === void 0 ? void 0 : rowSubTotal[rowLevel]) === null || _d === void 0 ? void 0 : _d.data; + var val = void 0; + if (path.length && rowSubTotal) { + path.push(quotaField); + val = lodash_es_1.get(data, path); + } + return val; + } + // 行总计里面的列小计 + if (status.isRowTotal && status.isColSubTotal) { + var colSubInRowTotal = customCalc.colSubInRowTotal; + var colLevel = getSubLevel(query, col); + var data = (_e = colSubInRowTotal === null || colSubInRowTotal === void 0 ? void 0 : colSubInRowTotal[colLevel]) === null || _e === void 0 ? void 0 : _e.data; + var colPath = getTreePath(query, col); + var val = void 0; + if (colPath.length && colSubInRowTotal) { + colPath.push(quotaField); + val = lodash_es_1.get(data, colPath); + } + return val; + } + // 列总计里面的行小计 + if (status.isColTotal && status.isRowSubTotal) { + var rowSubInColTotal = customCalc.rowSubInColTotal; + var rowSubLevel = getSubLevel(query, row); + var data = (_f = rowSubInColTotal === null || rowSubInColTotal === void 0 ? void 0 : rowSubInColTotal[rowSubLevel]) === null || _f === void 0 ? void 0 : _f.data; + var path = getTreePath(query, row); + var val = void 0; + if (path.length && rowSubInColTotal) { + path.push(quotaField); + val = lodash_es_1.get(data, path); + } + return val; + } + // 列小计里面的行小计 + if (status.isColSubTotal && status.isRowSubTotal) { + var rowSubInColSub = customCalc.rowSubInColSub; + var rowSubLevel = getSubLevel(query, row); + var colSubLevel = getSubLevel(query, col); + var data = (_h = (_g = rowSubInColSub === null || rowSubInColSub === void 0 ? void 0 : rowSubInColSub[rowSubLevel]) === null || _g === void 0 ? void 0 : _g[colSubLevel]) === null || _h === void 0 ? void 0 : _h.data; + var rowPath = getTreePath(query, row); + var colPath = getTreePath(query, col); + var path = __spreadArrays(rowPath, colPath); + var val = void 0; + if (path.length && rowSubInColSub) { + path.push(quotaField); + val = lodash_es_1.get(data, path); + } + return val; + } +} +function getCustomCalcResult(query, axisMap, chart, status, customCalc) { + var tableLayoutMode = chart.customAttr.basicStyle.tableLayoutMode; + if (tableLayoutMode === 'tree') { + return getTreeCustomCalcResult(query, axisMap, status, customCalc); + } + return getGridCustomCalcResult(query, axisMap, status, customCalc); +} +function getSubLevel(query, axis) { + var fields = axis.map(function (a) { return a.gisbiName; }); + var subLevel = -1; + var queryFields = lodash_es_1.keys(query); + var _loop_1 = function (i) { + var field = fields[i]; + var index = queryFields.findIndex(function (f) { return f === field; }); + if (index !== -1) { + subLevel++; + } + }; + for (var i = fields.length - 1; i >= 0; i--) { + _loop_1(i); + } + return subLevel; +} +function getTreePath(query, axis) { + var path = []; + var fields = lodash_es_1.keys(query); + axis.forEach(function (a) { + var index = fields.findIndex(function (f) { return f === a.gisbiName; }); + if (index !== -1) { + path.push(query[a.gisbiName]); + } + }); + return path; +} +function getAggregationAndCalcFuncByQuery(totalsStatus, totalsOptions) { + var isRowTotal = totalsStatus.isRowTotal, isRowSubTotal = totalsStatus.isRowSubTotal, isColTotal = totalsStatus.isColTotal, isColSubTotal = totalsStatus.isColSubTotal; + var _a = totalsOptions || {}, row = _a.row, col = _a.col; + var _b = row || {}, _c = _b.calcTotals, rowCalcTotals = _c === void 0 ? {} : _c, _d = _b.calcSubTotals, rowCalcSubTotals = _d === void 0 ? {} : _d; + var _e = col || {}, _f = _e.calcTotals, colCalcTotals = _f === void 0 ? {} : _f, _g = _e.calcSubTotals, colCalcSubTotals = _g === void 0 ? {} : _g; + var getCalcTotals = function (dimensionTotals, isTotal) { + if ((dimensionTotals.aggregation || dimensionTotals.calcFunc) && isTotal) { + return { + aggregation: dimensionTotals.aggregation, + calcFunc: dimensionTotals.calcFunc + }; + } + }; + // 优先级: 列总计/小计 > 行总计/小计 + return (getCalcTotals(colCalcTotals, isColTotal) || + getCalcTotals(colCalcSubTotals, isColSubTotal) || + getCalcTotals(rowCalcTotals, isRowTotal) || + getCalcTotals(rowCalcSubTotals, isRowSubTotal)); +} +exports.isNotNumber = function (value) { + if (typeof value === 'number') { + return Number.isNaN(value); + } + if (!value) { + return true; + } + if (typeof value === 'string') { + return Number.isNaN(Number(value)); + } + return true; +}; +var processFieldValues = function (data, field, filterIllegalValue) { + if (filterIllegalValue === void 0) { filterIllegalValue = false; } + if (!(data === null || data === void 0 ? void 0 : data.length)) { + return []; + } + return data.reduce(function (resultArr, item) { + var fieldValue = lodash_es_1.get(item, field); + var notNumber = exports.isNotNumber(fieldValue); + if (filterIllegalValue && notNumber) { + // 过滤非法值 + return resultArr; + } + var val = notNumber ? 0 : fieldValue; + resultArr.push(new decimal_js_1["default"](val)); + return resultArr; + }, []); +}; +exports.getDataSumByField = function (data, field) { + var fieldValues = processFieldValues(data, field); + if (!fieldValues.length) { + return 0; + } + return decimal_js_1["default"].sum.apply(decimal_js_1["default"], fieldValues).toNumber(); +}; +exports.getDataExtremumByField = function (method, data, field) { + // 防止预处理时默认值 0 影响极值结果,处理时需过滤非法值 + var fieldValues = processFieldValues(data, field, true); + if (!(fieldValues === null || fieldValues === void 0 ? void 0 : fieldValues.length)) { + return; + } + return decimal_js_1["default"][method].apply(decimal_js_1["default"], fieldValues).toNumber(); +}; +exports.getDataAvgByField = function (data, field) { + var fieldValues = processFieldValues(data, field); + if (!(fieldValues === null || fieldValues === void 0 ? void 0 : fieldValues.length)) { + return 0; + } + return decimal_js_1["default"].sum.apply(decimal_js_1["default"], fieldValues).dividedBy(fieldValues.length) + .toNumber(); +}; +var calcActionByType = (_a = {}, + _a[s2_1.Aggregation.SUM] = exports.getDataSumByField, + _a[s2_1.Aggregation.MIN] = function (data, field) { return exports.getDataExtremumByField('min', data, field); }, + _a[s2_1.Aggregation.MAX] = function (data, field) { return exports.getDataExtremumByField('max', data, field); }, + _a[s2_1.Aggregation.AVG] = exports.getDataAvgByField, + _a); +var EmptyDataCell = /** @class */ (function (_super) { + __extends(EmptyDataCell, _super); + function EmptyDataCell() { + return _super !== null && _super.apply(this, arguments) || this; + } + EmptyDataCell.prototype.drawTextShape = function () { + this.meta.fieldValue = ' '; + _super.prototype.drawTextShape.call(this); + var _a = this.spreadsheet.facet, rowHeader = _a.rowHeader, columnHeader = _a.columnHeader; + var offsetX = columnHeader.getConfig().viewportWidth / 2; + var offsetY = rowHeader.getConfig().viewportHeight / 2; + var style = this.getTextStyle(); + var config = { + attrs: __assign(__assign({}, style), { x: offsetX, y: offsetY, text: t('data_set.no_data'), opacity: 1, textAlign: 'center', textBaseline: 'middle' }) + }; + this.addShape('text', config); + }; + EmptyDataCell.prototype.drawBackgroundShape = function () { + var cellTheme = this.theme.dataCell.cell; + cellTheme.backgroundColor = setColorOpacity(cellTheme.backgroundColor, 1); + _super.prototype.drawBackgroundShape.call(this); + }; + return EmptyDataCell; +}(s2_1.MergedCell)); +function setColorOpacity(color, opacity) { + if (color.indexOf('rgba') !== -1) { + var colorArr = color.split(','); + colorArr[3] = opacity + ")"; + return colorArr.join(','); + } + if (color.indexOf('rgb') !== -1) { + return "" + color.replace('rgb', 'rgba').replace(')', "," + opacity + ")"); + } + if (color.indexOf('#') !== -1) { + if (color.length === 7) { + return "" + color + Math.round(opacity * 255).toString(16); + } + if (color.length === 9) { + return color.slice(0, 7) + Math.round(opacity * 255).toString(16); + } + } + return color; +} +exports.setColorOpacity = setColorOpacity; +function configEmptyDataStyle(instance, data) { + if (data === null || data === void 0 ? void 0 : data.length) { + return; + } + instance.on(s2_1.S2Event.LAYOUT_AFTER_RENDER, function () { + var _a; + var _b = ((_a = instance.facet) === null || _a === void 0 ? void 0 : _a.layoutResult) || {}, colLeafNodes = _b.colLeafNodes, rowLeafNodes = _b.rowLeafNodes; + if (!(colLeafNodes === null || colLeafNodes === void 0 ? void 0 : colLeafNodes.length) || !(rowLeafNodes === null || rowLeafNodes === void 0 ? void 0 : rowLeafNodes.length)) { + return; + } + var mergedCells = []; + colLeafNodes.forEach(function (_, colIndex) { + rowLeafNodes.forEach(function (__, rowIndex) { + mergedCells.push({ rowIndex: rowIndex, colIndex: colIndex }); + }); + }); + instance.options.mergedCell = function (s, c, m) { return new EmptyDataCell(s, c, m); }; + instance.interaction.mergeCells(mergedCells); + }); +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/table/t-heatmap.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/table/t-heatmap.ts index 8750439..bda12f7 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/table/t-heatmap.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/table/t-heatmap.ts @@ -119,11 +119,12 @@ export class TableHeatmap extends G2PlotChartView { if (!xAxis?.length || !xAxisExt?.length || !extColor?.length) { return } - const xField = xAxis[0].dataeaseName - const xFieldExt = xAxisExt[0].dataeaseName - const extColorField = extColor[0].dataeaseName + const xField = xAxis[0].gisbiName + const xFieldExt = xAxisExt[0].gisbiName + const extColorField = extColor[0].gisbiName // data - const data = cloneDeep(chart.data.tableRow) + const tmpData = cloneDeep(chart.data.tableRow) + const data = tmpData.filter(cell => cell[xField] && cell[xFieldExt] && cell[extColorField]) data.forEach(i => { Object.keys(i).forEach(key => { if (key === '*') { @@ -171,10 +172,10 @@ export class TableHeatmap extends G2PlotChartView { const dimensionList = [] chart.data.fields.forEach(item => { Object.keys(pointData).forEach(key => { - if (key.startsWith('f_') && item.dataeaseName === key) { + if (key.startsWith('f_') && item.gisbiName === key) { dimensionList.push({ id: item.id, - dataeaseName: item.dataeaseName, + gisbiName: item.gisbiName, value: pointData[key] }) } @@ -197,7 +198,7 @@ export class TableHeatmap extends G2PlotChartView { newChart.on('afterrender', ev => { const l = JSON.parse(JSON.stringify(parseJson(chart.customStyle).legend)) if (l.show) { - const rail = ev.view.getController('legend').option[extColor[0].dataeaseName]?.['rail'] + const rail = ev.view.getController('legend').option[extColor[0].gisbiName]?.['rail'] if (rail) { rail.defaultLength = this.getDefaultLength(chart, l) } @@ -207,6 +208,12 @@ export class TableHeatmap extends G2PlotChartView { return newChart } + protected configTheme(chart: Chart, options: HeatmapOptions): HeatmapOptions { + const tmp = super.configTheme(chart, options) + tmp.theme.innerLabels.offset = 0 + return tmp + } + protected configBasicStyle(chart: Chart, options: HeatmapOptions): HeatmapOptions { const basicStyle = parseJson(chart.customAttr).basicStyle const color = basicStyle.colors?.map(ele => { @@ -235,7 +242,7 @@ export class TableHeatmap extends G2PlotChartView { const items = [] const createItem = (fieldObj, items, originalItems) => { const name = fieldObj?.chartShowName ? fieldObj?.chartShowName : fieldObj?.name - let value = originalItems[0].data[fieldObj.dataeaseName] + let value = originalItems[0].data[fieldObj.gisbiName] if (!isNaN(Number(value))) { value = valueFormatter(value, fieldObj?.formatterCfg) } @@ -329,7 +336,7 @@ export class TableHeatmap extends G2PlotChartView { position: 'middle', layout, formatter: data => { - const value = data[extColor[0]?.dataeaseName] + const value = data[extColor[0]?.gisbiName] if (!isNaN(Number(value))) { return valueFormatter(value, extColor[0]?.formatterCfg) } diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/table/table-info.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/table/table-info.ts index 0485bcd..44a49b9 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/table/table-info.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/table/table-info.ts @@ -14,7 +14,7 @@ import { hexColorToRGBA, isAlphaColor, parseJson } from '../../../util' import { S2ChartView, S2DrawOptions } from '../../types/impl/s2' import { TABLE_EDITOR_PROPERTY, TABLE_EDITOR_PROPERTY_INNER } from './common' import { useI18n } from '@/data-visualization/hooks/web/useI18n' -import { isEqual, isNumber, merge } from 'lodash-es' +import { filter, isEqual, isNumber, merge } from 'lodash-es' import { copyContent, CustomDataCell, @@ -22,37 +22,19 @@ import { getRowIndex, calculateHeaderHeight, SortTooltip, - configSummaryRow, - summaryRowStyle, configEmptyDataStyle, getLeafNodes, - getColumns + getColumns, + drawImage, + getSummaryRow, + SummaryCell } from '@/data-visualization/chart/components/js/panel/common/common_table' const { t } = useI18n() + class ImageCell extends CustomDataCell { protected drawTextShape(): void { - const img = new Image() - const { x, y, width, height, fieldValue } = this.meta - img.src = fieldValue as string - img.setAttribute('crossOrigin', 'anonymous') - img.onload = () => { - !this.cfg.children && (this.cfg.children = []) - const { width: imgWidth, height: imgHeight } = img - const ratio = Math.max(imgWidth / width, imgHeight / height) - // 不铺满,部分留白 - const imgShowWidth = (imgWidth / ratio) * 0.8 - const imgShowHeight = (imgHeight / ratio) * 0.8 - this.textShape = this.addShape('image', { - attrs: { - x: x + (imgShowWidth < width ? (width - imgShowWidth) / 2 : 0), - y: y + (imgShowHeight < height ? (height - imgShowHeight) / 2 : 0), - width: imgShowWidth, - height: imgShowHeight, - img - } - }) - } + drawImage.apply(this) } } /** @@ -75,9 +57,7 @@ export class TableInfo extends S2ChartView { 'alpha', 'tablePageMode', 'showHoverStyle', - 'autoWrap', - 'showSummary', - 'summaryLabel' + 'autoWrap' ], 'table-cell-selector': [ ...TABLE_EDITOR_PROPERTY_INNER['table-cell-selector'], @@ -85,7 +65,8 @@ export class TableInfo extends S2ChartView { 'tableColumnFreezeHead', 'tableRowFreezeHead', 'mergeCells' - ] + ], + 'summary-selector': ['showSummary', 'summaryLabel'] } axis: AxisType[] = ['xAxis', 'filter', 'drill'] axisConfig: AxisConfig = { @@ -103,7 +84,7 @@ export class TableInfo extends S2ChartView { const columns = [] const meta = [] const axisMap = chart.xAxis.reduce((pre, cur) => { - pre[cur.dataeaseName] = cur + pre[cur.gisbiName] = cur return pre }, {}) const drillFieldMap = {} @@ -121,17 +102,17 @@ export class TableInfo extends S2ChartView { fields = fields.filter(ele => { return !filterFields.includes(ele.id) }) - drillFieldMap[curDrillField.dataeaseName] = chart.drillFields[0].dataeaseName + drillFieldMap[curDrillField.gisbiName] = chart.drillFields[0].gisbiName fields.splice(drillFieldIndex, 0, curDrillField) } fields.forEach(ele => { - const f = axisMap[ele.dataeaseName] + const f = axisMap[ele.gisbiName] if (f?.hide === true) { return } - columns.push(ele.dataeaseName) + columns.push(ele.gisbiName) meta.push({ - field: ele.dataeaseName, + field: ele.gisbiName, name: ele.chartShowName ?? ele.name, formatter: function (value) { if (!f) { @@ -140,7 +121,7 @@ export class TableInfo extends S2ChartView { if (value === null || value === undefined) { return value } - if (![2, 3].includes(f.deType) || !isNumber(value)) { + if (![2, 3, 4].includes(f.deType) || !isNumber(value)) { return value } let formatCfg = f.formatterCfg @@ -204,7 +185,7 @@ export class TableInfo extends S2ChartView { // 自适应列宽模式下,URL 字段的宽度固定为 120 if (basicStyle.tableColumnMode === 'adapt') { const urlFields = fields.filter( - field => field.deType === 7 && !axisMap[field.dataeaseName]?.hide + field => field.deType === 7 && !axisMap[field.gisbiName]?.hide ) s2Options.style.colCfg.widthByFieldValue = urlFields?.reduce((p, n) => { p[n.chartShowName ?? n.name] = 120 @@ -215,37 +196,6 @@ export class TableInfo extends S2ChartView { s2Options.frozenColCount = tableCell.tableColumnFreezeHead ?? 0 s2Options.frozenRowCount = tableCell.tableRowFreezeHead ?? 0 } - // 开启序号之后,第一列就是序号列,修改 label 即可 - if (s2Options.showSeriesNumber) { - let indexLabel = tableHeader.indexLabel - if (!indexLabel) { - indexLabel = '' - } - s2Options.layoutCoordinate = (_, __, col) => { - if (col.colIndex === 0 && col.rowIndex === 0) { - col.label = indexLabel - col.value = indexLabel - } - } - } - s2Options.dataCell = viewMeta => { - const field = fields.filter(f => f.dataeaseName === viewMeta.valueField)?.[0] - if (field?.deType === 7 && chart.showPosition !== 'dialog') { - return new ImageCell(viewMeta, viewMeta?.spreadsheet) - } - if (viewMeta.colIndex === 0 && s2Options.showSeriesNumber) { - if (tableCell.mergeCells) { - viewMeta.fieldValue = getRowIndex(s2Options.mergedCellsInfo, viewMeta) - } else { - viewMeta.fieldValue = - pageInfo.pageSize * (pageInfo.currentPage - 1) + viewMeta.rowIndex + 1 - } - } - // 配置文本自动换行参数 - viewMeta.autoWrap = tableCell.mergeCells ? false : basicStyle.autoWrap - viewMeta.maxLines = basicStyle.maxLines - return new CustomDataCell(viewMeta, viewMeta?.spreadsheet) - } // tooltip this.configTooltip(chart, s2Options) // 合并单元格 @@ -274,12 +224,12 @@ export class TableInfo extends S2ChartView { return new CustomTableColCell(node, sheet, config) } } - // 总计 - configSummaryRow(chart, s2Options, newData, tableHeader, basicStyle, basicStyle.showSummary) + // 序列号和总计行 + this.configSummaryRowAndIndex(chart, pageInfo, s2Options, s2DataConfig) // 开始渲染 const newChart = new TableSheet(containerDom, s2DataConfig, s2Options) // 总计紧贴在单元格后面 - summaryRowStyle(newChart, newData, tableCell, tableHeader, basicStyle.showSummary) + this.summaryRowStyle(newChart, newData, tableCell, tableHeader, basicStyle.showSummary) // 开启自动换行 if (basicStyle.autoWrap && !tableCell.mergeCells) { // 调整表头宽度时,计算表头高度 @@ -340,8 +290,8 @@ export class TableInfo extends S2ChartView { } // 第一次渲染初始化,把图片字段固定为 120 进行计算 const urlFields = fields - .filter(field => field.deType === 7 && !axisMap[field.dataeaseName]?.hide) - .map(f => f.dataeaseName) + .filter(field => field.deType === 7 && !axisMap[field.gisbiName]?.hide) + .map(f => f.gisbiName) const totalWidthWithImg = ev.colLeafNodes.reduce((p, n) => { return p + (urlFields.includes(n.field) ? 120 : n.width) }, 0) @@ -386,7 +336,7 @@ export class TableInfo extends S2ChartView { const cell = newChart.getCell(ev.target) const meta = cell.getMeta() as ViewMeta const nameIdMap = fields.reduce((pre, next) => { - pre[next['dataeaseName']] = next['id'] + pre[next['gisbiName']] = next['id'] return pre }, {}) @@ -417,13 +367,13 @@ export class TableInfo extends S2ChartView { newChart.on(S2Event.COL_CELL_HOVER, event => this.showTooltip(newChart, event, meta)) newChart.on(S2Event.DATA_CELL_HOVER, event => this.showTooltip(newChart, event, meta)) newChart.on(S2Event.MERGED_CELLS_HOVER, event => this.showTooltip(newChart, event, meta)) + // touch + this.configTouchEvent(newChart, drawOption, meta) } // header resize newChart.on(S2Event.LAYOUT_RESIZE_COL_WIDTH, ev => resizeAction(ev)) // right click newChart.on(S2Event.GLOBAL_CONTEXT_MENU, event => copyContent(newChart, event, meta)) - // touch - this.configTouchEvent(newChart, drawOption, meta) // theme const customTheme = this.configTheme(chart) newChart.setThemeCfg({ theme: customTheme }) @@ -444,6 +394,11 @@ export class TableInfo extends S2ChartView { const fontStyle = tableCell.isItalic ? 'italic' : 'normal' const fontWeight = tableCell.isBolder === false ? 'normal' : 'bold' const mergeCellTheme: S2Theme = { + dataCell: { + cell: { + crossBackgroundColor: tableItemBgColor + } + }, mergedCell: { cell: { backgroundColor: tableItemBgColor, @@ -488,6 +443,92 @@ export class TableInfo extends S2ChartView { return theme } + protected configSummaryRowAndIndex( + chart: Chart, + pageInfo: PageInfo, + s2Options: S2Options, + s2DataConfig: S2DataConfig + ) { + const { tableHeader, basicStyle, tableCell } = parseJson(chart.customAttr) + const fields = chart.data?.fields ?? [] + // 开启序号之后,第一列就是序号列,修改 label 即可 + if (s2Options.showSeriesNumber) { + let indexLabel = tableHeader.indexLabel + if (!indexLabel) { + indexLabel = '' + } + s2Options.layoutCoordinate = (_, __, col) => { + if (col.colIndex === 0 && col.rowIndex === 0) { + col.label = indexLabel + col.value = indexLabel + } + } + } + const { showSummary, summaryLabel } = basicStyle + const data = s2DataConfig.data + const xAxis = chart.xAxis + if (showSummary && data?.length) { + // 设置汇总行高度和表头一致 + const heightByField = {} + heightByField[data.length] = tableHeader.tableTitleHeight + s2Options.style.rowCfg = { heightByField } + // 计算汇总加入到数据里,冻结最后一行 + s2Options.frozenTrailingRowCount = 1 + const axis = filter(xAxis, axis => [2, 3, 4].includes(axis.deType)) + const summaryObj = getSummaryRow(data, axis, basicStyle.seriesSummary) as any + data.push(summaryObj) + } + s2Options.dataCell = viewMeta => { + // 总计行处理 + if (showSummary && viewMeta.rowIndex === data.length - 1) { + if (viewMeta.colIndex === 0) { + if (tableHeader.showIndex) { + viewMeta.fieldValue = summaryLabel ?? t('chart.total_show') + } else { + // 第一列不是数值类型的,显示总计 + if (![2, 3, 4].includes(xAxis?.[0]?.deType)) { + viewMeta.fieldValue = summaryLabel ?? t('chart.total_show') + } + } + } + return new SummaryCell(viewMeta, viewMeta?.spreadsheet) + } + const field = fields.find(f => f.gisbiName === viewMeta.valueField) + if (field?.deType === 7 && chart.showPosition !== 'dialog') { + return new ImageCell(viewMeta, viewMeta?.spreadsheet) + } + if (viewMeta.colIndex === 0 && s2Options.showSeriesNumber) { + if (tableCell.mergeCells) { + viewMeta.fieldValue = getRowIndex(s2Options.mergedCellsInfo, viewMeta) + } else { + viewMeta.fieldValue = + pageInfo.pageSize * (pageInfo.currentPage - 1) + viewMeta.rowIndex + 1 + } + } + // 配置文本自动换行参数 + viewMeta.autoWrap = tableCell.mergeCells ? false : basicStyle.autoWrap + viewMeta.maxLines = basicStyle.maxLines + return new CustomDataCell(viewMeta, viewMeta?.spreadsheet) + } + } + + protected summaryRowStyle(newChart: TableSheet, newData, tableCell, tableHeader, showSummary) { + if (!showSummary || !newData.length) return + const columns = newChart.dataCfg.fields.columns + const showHeader = tableHeader.showTableHeader === true + // 不显示表头时,减少一个表头的高度 + const headerAndSummaryHeight = showHeader ? getMaxTreeDepth(columns) + 1 : 1 + newChart.on(S2Event.LAYOUT_BEFORE_RENDER, () => { + const totalHeight = + tableHeader.tableTitleHeight * headerAndSummaryHeight + + tableCell.tableItemHeight * (newData.length - 1) + if (totalHeight < newChart.container.cfg.height) { + newChart.options.height = + totalHeight < newChart.container.cfg.height - 8 ? totalHeight + 8 : totalHeight + } + }) + } + constructor() { super('table-info', []) } @@ -508,3 +549,17 @@ function getStartPosition(node) { } return getStartPosition(node.children[0]) } + +function getMaxTreeDepth(nodes) { + if (!nodes?.length) { + return 0 + } + return Math.max( + ...nodes.map(node => { + if (!node.children?.length) { + return 1 + } + return getMaxTreeDepth(node.children) + 1 + }) + ) +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/table/table-normal.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/table/table-normal.ts index 327dd5b..ffb0b43 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/table/table-normal.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/table/table-normal.ts @@ -2,10 +2,11 @@ import { useI18n } from '@/data-visualization/hooks/web/useI18n' import { formatterItem, valueFormatter } from '@/data-visualization/chart/components/js/formatter' import { configEmptyDataStyle, - configSummaryRow, copyContent, + CustomDataCell, + getSummaryRow, SortTooltip, - summaryRowStyle + SummaryCell } from '@/data-visualization/chart/components/js/panel/common/common_table' import { S2ChartView, S2DrawOptions } from '@/data-visualization/chart/components/js/panel/types/impl/s2' import { parseJson } from '@/data-visualization/chart/components/js/util' @@ -19,7 +20,7 @@ import { TableSheet, ViewMeta } from '@antv/s2' -import { cloneDeep, isNumber } from 'lodash-es' +import { isNumber } from 'lodash-es' import { TABLE_EDITOR_PROPERTY, TABLE_EDITOR_PROPERTY_INNER } from './common' const { t } = useI18n() @@ -37,8 +38,7 @@ export class TableNormal extends S2ChartView { ], 'basic-style-selector': [ ...TABLE_EDITOR_PROPERTY_INNER['basic-style-selector'], - 'showSummary', - 'summaryLabel', + 'tablePageMode', 'showHoverStyle' ], 'table-cell-selector': [ @@ -46,7 +46,8 @@ export class TableNormal extends S2ChartView { 'tableFreeze', 'tableColumnFreezeHead', 'tableRowFreezeHead' - ] + ], + 'summary-selector': ['showSummary', 'summaryLabel'] } axis: AxisType[] = ['xAxis', 'yAxis', 'drill', 'filter'] axisConfig: AxisConfig = { @@ -66,7 +67,7 @@ export class TableNormal extends S2ChartView { } drawChart(drawOption: S2DrawOptions): TableSheet { - const { container, chart, action, resizeAction } = drawOption + const { container, chart, action, pageInfo, resizeAction } = drawOption const containerDom = document.getElementById(container) if (!containerDom) return @@ -92,18 +93,18 @@ export class TableNormal extends S2ChartView { fields.splice(drillFieldIndex, 0, ...curDrillField) } const axisMap = [...chart.xAxis, ...chart.yAxis].reduce((pre, cur) => { - pre[cur.dataeaseName] = cur + pre[cur.gisbiName] = cur return pre }, {}) // add drill list fields.forEach(ele => { - const f = axisMap[ele.dataeaseName] + const f = axisMap[ele.gisbiName] if (f?.hide === true) { return } - columns.push(ele.dataeaseName) + columns.push(ele.gisbiName) meta.push({ - field: ele.dataeaseName, + field: ele.gisbiName, name: ele.chartShowName ?? ele.name, formatter: function (value) { if (!f) { @@ -112,7 +113,7 @@ export class TableNormal extends S2ChartView { if (value === null || value === undefined) { return value } - if (![2, 3].includes(f.deType) || !isNumber(value)) { + if (![2, 3, 4].includes(f.deType) || !isNumber(value)) { return value } let formatCfg = f.formatterCfg @@ -160,19 +161,6 @@ export class TableNormal extends S2ChartView { s2Options.frozenColCount = tableCell.tableColumnFreezeHead ?? 0 s2Options.frozenRowCount = tableCell.tableRowFreezeHead ?? 0 } - // 开启序号之后,第一列就是序号列,修改 label 即可 - if (s2Options.showSeriesNumber) { - let indexLabel = tableHeader.indexLabel - if (!indexLabel) { - indexLabel = '' - } - s2Options.layoutCoordinate = (_, __, col) => { - if (col.colIndex === 0 && col.rowIndex === 0) { - col.label = indexLabel - col.value = indexLabel - } - } - } // tooltip this.configTooltip(chart, s2Options) // 隐藏表头,保留顶部的分割线, 禁用表头横向 resize @@ -193,13 +181,12 @@ export class TableNormal extends S2ChartView { chart.container = container this.configHeaderInteraction(chart, s2Options) } - - // 总计 - configSummaryRow(chart, s2Options, newData, tableHeader, basicStyle, basicStyle.showSummary) + // 配置总计和序号列 + this.configSummaryRowAndIndex(chart, pageInfo, s2Options, s2DataConfig) // 开始渲染 const newChart = new TableSheet(containerDom, s2DataConfig, s2Options) // 总计紧贴在单元格后面 - summaryRowStyle(newChart, newData, tableCell, tableHeader, basicStyle.showSummary) + this.summaryRowStyle(newChart, newData, tableCell, tableHeader, basicStyle.showSummary) // 自适应铺满 if (basicStyle.tableColumnMode === 'adapt') { newChart.on(S2Event.LAYOUT_RESIZE_COL_WIDTH, () => { @@ -253,7 +240,7 @@ export class TableNormal extends S2ChartView { const cell = newChart.getCell(ev.target) const meta = cell.getMeta() as ViewMeta const nameIdMap = fields.reduce((pre, next) => { - pre[next['dataeaseName']] = next['id'] + pre[next['gisbiName']] = next['id'] return pre }, {}) @@ -281,19 +268,86 @@ export class TableNormal extends S2ChartView { if (show) { newChart.on(S2Event.COL_CELL_HOVER, event => this.showTooltip(newChart, event, meta)) newChart.on(S2Event.DATA_CELL_HOVER, event => this.showTooltip(newChart, event, meta)) + // touch + this.configTouchEvent(newChart, drawOption, meta) } // header resize newChart.on(S2Event.LAYOUT_RESIZE_COL_WIDTH, ev => resizeAction(ev)) // right click newChart.on(S2Event.GLOBAL_CONTEXT_MENU, event => copyContent(newChart, event, meta)) - // touch - this.configTouchEvent(newChart, drawOption, meta) // theme const customTheme = this.configTheme(chart) newChart.setThemeCfg({ theme: customTheme }) return newChart } + + protected configSummaryRowAndIndex( + chart: Chart, + pageInfo: PageInfo, + s2Options: S2Options, + s2DataConfig: S2DataConfig + ) { + const { tableHeader, basicStyle } = parseJson(chart.customAttr) + // 开启序号之后,第一列就是序号列,修改 label 即可 + if (s2Options.showSeriesNumber) { + let indexLabel = tableHeader.indexLabel + if (!indexLabel) { + indexLabel = '' + } + s2Options.layoutCoordinate = (_, __, col) => { + if (col.colIndex === 0 && col.rowIndex === 0) { + col.label = indexLabel + col.value = indexLabel + } + } + } + const { showSummary, summaryLabel } = basicStyle + const data = s2DataConfig.data + const { xAxis, yAxis } = chart + if (showSummary && data?.length) { + // 设置汇总行高度和表头一致 + const heightByField = {} + heightByField[data.length] = tableHeader.tableTitleHeight + s2Options.style.rowCfg = { heightByField } + // 计算汇总加入到数据里,冻结最后一行 + s2Options.frozenTrailingRowCount = 1 + const summaryObj = getSummaryRow(data, yAxis, basicStyle.seriesSummary) as any + data.push(summaryObj) + } + s2Options.dataCell = viewMeta => { + // 总计行处理 + if (showSummary && viewMeta.rowIndex === data.length - 1) { + if (viewMeta.colIndex === 0) { + if (tableHeader.showIndex || xAxis?.length) { + viewMeta.fieldValue = summaryLabel ?? t('chart.total_show') + } + } + return new SummaryCell(viewMeta, viewMeta?.spreadsheet) + } + if (viewMeta.colIndex === 0 && s2Options.showSeriesNumber) { + viewMeta.fieldValue = pageInfo.pageSize * (pageInfo.currentPage - 1) + viewMeta.rowIndex + 1 + } + return new CustomDataCell(viewMeta, viewMeta?.spreadsheet) + } + } + + protected summaryRowStyle(newChart, newData, tableCell, tableHeader, showSummary) { + if (!showSummary || !newData.length) return + newChart.on(S2Event.LAYOUT_BEFORE_RENDER, () => { + const showHeader = tableHeader.showTableHeader === true + // 不显示表头时,减少一个表头的高度 + const headerAndSummaryHeight = showHeader ? 2 : 1 + const totalHeight = + tableHeader.tableTitleHeight * headerAndSummaryHeight + + tableCell.tableItemHeight * (newData.length - 1) + if (totalHeight < newChart.container.cfg.height) { + newChart.options.height = + totalHeight < newChart.container.cfg.height - 8 ? totalHeight + 8 : totalHeight + } + }) + } + constructor() { super('table-normal', []) } diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/table/table-pivot.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/table/table-pivot.ts index f7f695c..bf6fe22 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/charts/table/table-pivot.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/table/table-pivot.ts @@ -13,7 +13,8 @@ import { TotalStatus, Aggregation, S2DataConfig, - MergedCell + MergedCell, + LayoutResult } from '@antv/s2' import { formatterItem, valueFormatter } from '../../../formatter' import { hexColorToRGBA, isAlphaColor, parseJson } from '../../../util' @@ -91,7 +92,8 @@ export class TablePivot extends S2ChartView { 'showColTooltip', 'showRowTooltip', 'showHorizonBorder', - 'showVerticalBorder' + 'showVerticalBorder', + 'rowHeaderFreeze' ], 'table-total-selector': ['row', 'col'], 'basic-style-selector': [ @@ -100,7 +102,9 @@ export class TablePivot extends S2ChartView { 'tableScrollBarColor', 'alpha', 'tableLayoutMode', - 'showHoverStyle' + 'showHoverStyle', + 'quotaPosition', + 'quotaColLabel' ] } axis: AxisType[] = ['xAxis', 'xAxisExt', 'yAxis', 'filter'] @@ -126,7 +130,7 @@ export class TablePivot extends S2ChartView { const { xAxisExt: columnFields, xAxis: rowFields, yAxis: valueFields } = chart const [c, r, v] = [columnFields, rowFields, valueFields].map(arr => - arr.map(i => i.dataeaseName) + arr.map(i => i.gisbiName) ) // fields @@ -146,14 +150,14 @@ export class TablePivot extends S2ChartView { ...chart.xAxisExt, ...chart.yAxis ].reduce((p, n) => { - p[n.dataeaseName] = n + p[n.gisbiName] = n return p }, {}) fields.forEach(ele => { - const f = valueFieldMap[ele.dataeaseName] - columns.push(ele.dataeaseName) + const f = valueFieldMap[ele.gisbiName] + columns.push(ele.gisbiName) meta.push({ - field: ele.dataeaseName, + field: ele.gisbiName, name: ele.chartShowName ?? ele.name, formatter: value => { if (!f) { @@ -162,7 +166,7 @@ export class TablePivot extends S2ChartView { if (value === null || value === undefined) { return value } - if (![2, 3].includes(f.deType) || !isNumber(value)) { + if (![2, 3, 4].includes(f.deType) || !isNumber(value)) { return value } if (f.formatterCfg) { @@ -175,7 +179,7 @@ export class TablePivot extends S2ChartView { }) // total config - const { basicStyle, tooltip, tableTotal } = parseJson(chart.customAttr) + const { basicStyle, tooltip, tableTotal, tableHeader } = parseJson(chart.customAttr) if (!tableTotal.row.subTotalsDimensionsNew || tableTotal.row.subTotalsDimensions == undefined) { tableTotal.row.subTotalsDimensions = r } @@ -183,6 +187,7 @@ export class TablePivot extends S2ChartView { // 解析合计、小计排序 const sortParams = [] + let rowTotalSort = false if ( tableTotal.row.totalSort && tableTotal.row.totalSort !== 'none' && @@ -190,16 +195,20 @@ export class TablePivot extends S2ChartView { tableTotal.row.showGrandTotals && v.indexOf(tableTotal.row.totalSortField) > -1 ) { - const sort = { - sortFieldId: c[0], - sortMethod: tableTotal.row.totalSort.toUpperCase(), - sortByMeasure: TOTAL_VALUE, - query: { - [EXTRA_FIELD]: tableTotal.row.totalSortField + c.forEach(i => { + const sort = { + sortFieldId: i, + sortMethod: tableTotal.row.totalSort.toUpperCase(), + sortByMeasure: TOTAL_VALUE, + query: { + [EXTRA_FIELD]: tableTotal.row.totalSortField + } } - } - sortParams.push(sort) + sortParams.push(sort) + }) + rowTotalSort = true } + let colTotalSort = false if ( tableTotal.col.totalSort && tableTotal.col.totalSort !== 'none' && @@ -207,15 +216,18 @@ export class TablePivot extends S2ChartView { tableTotal.col.showGrandTotals && v.indexOf(tableTotal.col.totalSortField) > -1 ) { - const sort = { - sortFieldId: r[0], - sortMethod: tableTotal.col.totalSort.toUpperCase(), - sortByMeasure: TOTAL_VALUE, - query: { - [EXTRA_FIELD]: tableTotal.col.totalSortField + r.forEach(i => { + const sort = { + sortFieldId: i, + sortMethod: tableTotal.col.totalSort.toUpperCase(), + sortByMeasure: TOTAL_VALUE, + query: { + [EXTRA_FIELD]: tableTotal.col.totalSortField + } } - } - sortParams.push(sort) + sortParams.push(sort) + }) + colTotalSort = true } //列维度为空,行排序按照指标列来排序,取第一个有排序设置的指标 if (!columnFields?.length) { @@ -226,7 +238,7 @@ export class TablePivot extends S2ChartView { sortMethod: sortField.sort.toUpperCase(), sortByMeasure: TOTAL_VALUE, query: { - [EXTRA_FIELD]: sortField.dataeaseName + [EXTRA_FIELD]: sortField.gisbiName } } sortParams.push(sort) @@ -244,15 +256,29 @@ export class TablePivot extends S2ChartView { col: chart.xAxisExt, quota: chart.yAxis } - //树形模式下,列维度为空,行小计会变成列总计,特殊处理下 - if (basicStyle.tableLayoutMode === 'tree' && !chart.xAxisExt?.length) { - tableTotal.col.calcTotals = tableTotal.row.calcSubTotals + // 沒有列维度需要特殊处理 + if (!chart.xAxisExt?.length) { + //树形模式下,列维度为空,行小计的配置会变成列总计 + if (basicStyle.tableLayoutMode === 'tree') { + tableTotal.col.calcTotals = tableTotal.row.calcSubTotals + if (!tableTotal.col.calcTotals.cfg?.length) { + tableTotal.col.calcTotals.cfg = chart.yAxis.map(y => { + return { + gisbiName: y.gisbiName, + aggregation: 'SUM' + } + }) + } + } else { + // 列总计设置为空 + tableTotal.col.calcTotals.calcFunc = () => '-' + } } totals.forEach(total => { if (total.cfg?.length) { delete total.aggregation const totalCfgMap = total.cfg.reduce((p, n) => { - p[n.dataeaseName] = n + p[n.gisbiName] = n return p }, {}) total.calcFunc = (query, data, _, status) => { @@ -262,12 +288,93 @@ export class TablePivot extends S2ChartView { }) // 空值处理 const newData = this.configEmptyDataStrategy(chart) + // 行列维度排序 + if (!rowTotalSort) { + c?.forEach((f, i) => { + if (valueFieldMap[f]?.sort === 'none') { + return + } + const sort = { + sortFieldId: f + } + const sortMethod = valueFieldMap[f]?.sort?.toUpperCase() + if (sortMethod === 'CUSTOM_SORT') { + sort.sortBy = valueFieldMap[f].customSort + } else { + if (i === 0) { + sort.sortMethod = sortMethod + } else { + const fieldValues = newData.map(item => item[f]) + const uniqueValues = [...new Set(fieldValues)] + + // 根据配置动态决定排序顺序 + uniqueValues.sort((a, b) => { + if ([2, 3, 4].includes(valueFieldMap[f]?.deType)) { + return sortMethod === 'ASC' ? a - b : b - a + } + if (!a && !b) { + return 0 + } + if (!a) { + return sortMethod === 'ASC' ? -1 : 1 + } + if (!b) { + return sortMethod === 'ASC' ? 1 : -1 + } + return sortMethod === 'ASC' ? a.localeCompare(b) : b.localeCompare(a) + }) + sort.sortBy = uniqueValues + } + } + sortParams.push(sort) + }) + } + if (!colTotalSort) { + r?.forEach((f, i) => { + if (valueFieldMap[f]?.sort === 'none') { + return + } + const sort = { + sortFieldId: f + } + const sortMethod = valueFieldMap[f]?.sort?.toUpperCase() + if (sortMethod === 'CUSTOM_SORT') { + sort.sortBy = valueFieldMap[f].customSort + } else { + if (i === 0) { + sort.sortMethod = sortMethod + } else { + const fieldValues = newData.map(item => item[f]) + const uniqueValues = [...new Set(fieldValues)] + // 根据配置动态决定排序顺序 + uniqueValues.sort((a, b) => { + if ([2, 3, 4].includes(valueFieldMap[f]?.deType)) { + return sortMethod === 'ASC' ? a - b : b - a + } + if (!a && !b) { + return 0 + } + if (!a) { + return sortMethod === 'ASC' ? -1 : 1 + } + if (!b) { + return sortMethod === 'ASC' ? 1 : -1 + } + return sortMethod === 'ASC' ? a.localeCompare(b) : b.localeCompare(a) + }) + sort.sortBy = uniqueValues + } + } + sortParams.push(sort) + }) + } // data config const s2DataConfig: S2DataConfig = { fields: { rows: r, columns: c, - values: v + values: v, + valueInCols: !(basicStyle.quotaPosition === 'row') }, meta: meta, data: newData, @@ -277,6 +384,7 @@ export class TablePivot extends S2ChartView { width: containerDom.offsetWidth, height: containerDom.offsetHeight, totals: tableTotal as Totals, + cornerExtraFieldText: basicStyle.quotaColLabel ?? t('dataset.value'), conditions: this.configConditions(chart), tooltip: { getContainer: () => containerDom @@ -288,21 +396,204 @@ export class TablePivot extends S2ChartView { }, dataCell: meta => { return new CustomDataCell(meta, meta.spreadsheet) - } + }, + frozenRowHeader: !(tableHeader.rowHeaderFreeze === false) } // options s2Options.style = this.configStyle(chart, s2DataConfig) - s2Options.style.hierarchyCollapse = true + // 默认展开层级 + if (basicStyle.tableLayoutMode === 'tree') { + const { defaultExpandLevel } = basicStyle + if (isNumber(defaultExpandLevel)) { + if (defaultExpandLevel >= chart.xAxis.length) { + s2Options.style.rowExpandDepth = defaultExpandLevel + } else { + s2Options.style.rowExpandDepth = defaultExpandLevel - 2 + } + } + if (defaultExpandLevel === 'all') { + s2Options.style.rowExpandDepth = chart.xAxis.length + } + if (!defaultExpandLevel) { + s2Options.style.hierarchyCollapse = true + } + } + // 列汇总别名 + if (!(basicStyle.quotaPosition === 'row' && basicStyle.tableLayoutMode === 'tree')) { + if ( + basicStyle.quotaPosition !== 'row' && + chart.xAxisExt?.length && + chart.yAxis?.length > 1 && + tableTotal.col.showGrandTotals && + tableTotal.col.calcTotals?.cfg?.length + ) { + const colTotalCfgMap = tableTotal.col.calcTotals.cfg.reduce((p, n) => { + p[n.gisbiName] = n + return p + }, {}) + s2Options.layoutCoordinate = (_, __, col) => { + if (col?.isGrandTotals) { + if (colTotalCfgMap[col.value]?.label) { + col.label = colTotalCfgMap[col.value].label + } + } + } + } + if ( + basicStyle.quotaPosition === 'row' && + chart.xAxisExt?.length && + chart.yAxis?.length > 1 && + tableTotal.row.showGrandTotals && + tableTotal.row.calcTotals?.cfg?.length + ) { + const rowTotalCfgMap = tableTotal.row.calcTotals.cfg.reduce((p, n) => { + p[n.gisbiName] = n + return p + }, {}) + // eslint-disable-next-line + s2Options.layoutCoordinate = (_, row, __) => { + if (row?.isGrandTotals) { + if (rowTotalCfgMap[row.value]?.label) { + row.label = rowTotalCfgMap[row.value].label + } + } + } + } + } // tooltip this.configTooltip(chart, s2Options) // 开始渲染 const s2 = new PivotSheet(containerDom, s2DataConfig, s2Options as unknown as S2Options) + // 自适应铺满 + if (basicStyle.tableColumnMode === 'adapt') { + s2.on(S2Event.LAYOUT_RESIZE_COL_WIDTH, () => { + s2.store.set('lastLayoutResult', s2.facet.layoutResult) + }) + // 平铺模式行头resize + s2.on(S2Event.LAYOUT_RESIZE_ROW_WIDTH, () => { + s2.store.set('lastLayoutResult', s2.facet.layoutResult) + }) + // 树形模式行头resize + s2.on(S2Event.LAYOUT_RESIZE_TREE_WIDTH, () => { + s2.store.set('lastLayoutResult', s2.facet.layoutResult) + }) + s2.on(S2Event.LAYOUT_AFTER_HEADER_LAYOUT, (ev: LayoutResult) => { + const lastLayoutResult = s2.store.get('lastLayoutResult') as LayoutResult + if (lastLayoutResult) { + // 拖动 col 表头 resize + const colWidthByFieldValue = s2.options.style?.colCfg?.widthByFieldValue + // 平铺模式拖动 row 表头 resize + const rowWidthByField = s2.options.style?.rowCfg?.widthByField + // 树形模式拖动 row 表头 resize + const treeRowWidth = + s2.options.style?.treeRowsWidth || lastLayoutResult.rowsHierarchy.width + const colWidthMap = + lastLayoutResult.colLeafNodes.reduce((p, n) => { + p[n.id] = colWidthByFieldValue?.[n.value] ?? n.width + return p + }, {}) || {} + const totalColWidth = ev.colLeafNodes.reduce((p, n) => { + n.width = colWidthMap[n.id] || n.width + n.x = p + return p + n.width + }, 0) + ev.colNodes.forEach(n => { + if (n.isLeaf) { + return + } + n.width = this.getColWidth(n) + n.x = this.getLeftChild(n).x + }) + if (basicStyle.tableLayoutMode === 'tree') { + ev.rowNodes.forEach(n => { + n.width = treeRowWidth + }) + ev.rowsHierarchy.width = treeRowWidth + ev.colsHierarchy.width = totalColWidth + } else { + const rowWidthMap = + lastLayoutResult.rowNodes.reduce((p, n) => { + p[n.id] = rowWidthByField?.[n.field] ?? n.width + return p + }, {}) || {} + ev.rowNodes.forEach(n => { + n.x = 0 + n.width = rowWidthMap[n.id] || n.width + let tmp = n + while (tmp.parent.id !== 'root') { + n.x += tmp.parent.width + tmp = tmp.parent + } + }) + const totlaRowWidth = ev.rowsHierarchy.sampleNodesForAllLevels.reduce((p, n) => { + return p + n.width + }, 0) + const maxRowLevel = ev.rowsHierarchy.maxLevel + ev.rowNodes.forEach(n => { + // 总计和中间层级的小计需要重新计算宽度 + if (n.isTotalRoot || (n.isSubTotals && n.level < maxRowLevel)) { + let width = 0 + for (let i = n.level; i <= maxRowLevel; i++) { + width += ev.rowsHierarchy.sampleNodesForAllLevels[i].width + } + n.width = width + } + }) + ev.rowsHierarchy.width = totlaRowWidth + ev.colsHierarchy.width = totalColWidth + } + s2.store.set('lastLayoutResult', undefined) + return + } + const containerWidth = containerDom.getBoundingClientRect().width + const scale = containerWidth / (ev.colsHierarchy.width + ev.rowsHierarchy.width) + if (scale <= 1) { + return + } + const totalRowWidth = Math.round(ev.rowsHierarchy.width * scale) + ev.rowNodes.forEach(n => { + n.width = Math.round(n.width * scale) + }) + if (basicStyle.tableLayoutMode !== 'tree') { + ev.rowNodes.forEach(n => { + n.x = 0 + let tmp = n + while (tmp.parent.id !== 'root') { + n.x += tmp.parent.width + tmp = tmp.parent + } + }) + } + let totalColWidth = ev.colLeafNodes.reduce((p, n) => { + n.width = Math.round(n.width * scale) + n.x = p + return p + n.width + }, 0) + ev.colNodes.forEach(n => { + if (n.isLeaf) { + return + } + n.width = this.getColWidth(n) + n.x = this.getLeftChild(n).x + }) + const totalWidth = totalColWidth + totalRowWidth + if (totalWidth > containerWidth) { + // 从最后一列减掉 + ev.colLeafNodes[ev.colLeafNodes.length - 1].width -= totalWidth - containerWidth + totalColWidth = totalColWidth - (totalWidth - containerWidth) + } + ev.colsHierarchy.width = totalColWidth + ev.rowsHierarchy.width = totalRowWidth + }) + } // tooltip const { show } = tooltip if (show) { s2.on(S2Event.COL_CELL_HOVER, event => this.showTooltip(s2, event, meta)) s2.on(S2Event.ROW_CELL_HOVER, event => this.showTooltip(s2, event, meta)) s2.on(S2Event.DATA_CELL_HOVER, event => this.showTooltip(s2, event, meta)) + // touch + this.configTouchEvent(s2, drawOption, meta) } // empty data tip configEmptyDataStyle(s2, newData) @@ -312,19 +603,34 @@ export class TablePivot extends S2ChartView { s2.on(S2Event.COL_CELL_CLICK, ev => this.headerCellClickAction(chart, ev, s2, action)) // right click s2.on(S2Event.GLOBAL_CONTEXT_MENU, event => copyContent(s2, event, meta)) - // touch - this.configTouchEvent(s2, drawOption, meta) // theme const customTheme = this.configTheme(chart) s2.setThemeCfg({ theme: customTheme }) return s2 } + private getColWidth(node) { + let width = 0 + if (node.children?.length) { + node.children.forEach(child => { + width += this.getColWidth(child) + }) + } else { + width = node.width + } + return width + } + private getLeftChild(node) { + if (!node.children?.length) { + return node + } + return this.getLeftChild(node.children[0]) + } private dataCellClickAction(chart: Chart, ev, s2Instance: PivotSheet, callback) { const cell = s2Instance.getCell(ev.target) const meta = cell.getMeta() const nameIdMap = chart.data.fields.reduce((pre, next) => { - pre[next['dataeaseName']] = next['id'] + pre[next['gisbiName']] = next['id'] return pre }, {}) const rowData = { ...meta.rowQuery, ...meta.colQuery } @@ -352,7 +658,7 @@ export class TablePivot extends S2ChartView { const meta = cell.getMeta() const rowData = meta.query const nameIdMap = chart.data.fields.reduce((pre, next) => { - pre[next['dataeaseName']] = next['id'] + pre[next['gisbiName']] = next['id'] return pre }, {}) const dimensionList = [] @@ -522,7 +828,7 @@ export class TablePivot extends S2ChartView { } function customCalcFunc(query, data, status, chart, totalCfgMap, axisMap, customCalc) { if (!data?.length || !query[EXTRA_FIELD]) { - return 0 + return '-' } const aggregation = totalCfgMap[query[EXTRA_FIELD]]?.aggregation || 'SUM' switch (aggregation) { @@ -549,10 +855,13 @@ function customCalcFunc(query, data, status, chart, totalCfgMap, axisMap, custom }) return result?.[query[EXTRA_FIELD]] } + case 'NONE': { + return '-' + } case 'CUSTOM': { const val = getCustomCalcResult(query, axisMap, chart, status, customCalc || {}) - if (val === '') { - return val + if (val === '' || val === undefined) { + return '-' } return parseFloat(val) } @@ -593,11 +902,17 @@ function getTreeCustomCalcResult(query, axisMap, status: TotalStatus, customCalc // 列小计 if (status.isColSubTotal && !status.isRowTotal && !status.isRowSubTotal) { const { colSubTotal } = customCalc - const subLevel = getSubLevel(query, col) + const subColLevel = getSubLevel(query, col) + const subRowLevel = getSubLevel(query, row) const rowPath = getTreePath(query, row) const colPath = getTreePath(query, col) const path = [...rowPath, ...colPath] - const data = colSubTotal?.[subLevel]?.data + let data = colSubTotal?.[subColLevel]?.data + // 列小计里面的行小计 + if (rowPath.length < row.length) { + const { rowSubInColSub } = customCalc + data = rowSubInColSub?.[subRowLevel]?.[subColLevel]?.data + } let val if (path.length && data) { path.push(quotaField) @@ -647,7 +962,7 @@ function getTreeCustomCalcResult(query, axisMap, status: TotalStatus, customCalc if (status.isRowTotal && status.isColSubTotal) { const { colSubInRowTotal } = customCalc const colLevel = getSubLevel(query, col) - const { data } = colSubInRowTotal?.[colLevel] + const data = colSubInRowTotal?.[colLevel]?.data const colPath = getTreePath(query, col) let val if (colPath.length && colSubInRowTotal) { @@ -669,23 +984,7 @@ function getTreeCustomCalcResult(query, axisMap, status: TotalStatus, customCalc } return val } - // 列小计里面的行小计 - if (status.isColSubTotal && status.isRowSubTotal) { - const { rowSubInColSub } = customCalc - const rowSubLevel = getSubLevel(query, row) - const colSubLevel = getSubLevel(query, col) - const data = rowSubInColSub?.[rowSubLevel]?.[colSubLevel]?.data - const rowPath = getTreePath(query, row) - const colPath = getTreePath(query, col) - const path = [...rowPath, ...colPath] - let val - if (path.length && rowSubInColSub) { - path.push(quotaField) - val = get(data, path) - } - return val - } - return NaN + return '-' } function getGridCustomCalcResult(query, axisMap, status: TotalStatus, customCalc) { @@ -759,7 +1058,7 @@ function getGridCustomCalcResult(query, axisMap, status: TotalStatus, customCalc if (status.isRowTotal && status.isColSubTotal) { const { colSubInRowTotal } = customCalc const colLevel = getSubLevel(query, col) - const { data } = colSubInRowTotal?.[colLevel] + const data = colSubInRowTotal?.[colLevel]?.data const colPath = getTreePath(query, col) let val if (colPath.length && colSubInRowTotal) { @@ -807,7 +1106,7 @@ function getCustomCalcResult(query, axisMap, chart: ChartObj, status: TotalStatu } function getSubLevel(query, axis) { - const fields: [] = axis.map(a => a.dataeaseName) + const fields: [] = axis.map(a => a.gisbiName) let subLevel = -1 const queryFields = keys(query) for (let i = fields.length - 1; i >= 0; i--) { @@ -824,9 +1123,9 @@ function getTreePath(query, axis) { const path = [] const fields = keys(query) axis.forEach(a => { - const index = fields.findIndex(f => f === a.dataeaseName) + const index = fields.findIndex(f => f === a.gisbiName) if (index !== -1) { - path.push(query[a.dataeaseName]) + path.push(query[a.gisbiName]) } }) return path diff --git a/frontend/src/data-visualization/chart/components/js/panel/common/common_antv.ts b/frontend/src/data-visualization/chart/components/js/panel/common/common_antv.ts index 8bc7d32..aec9f36 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/common/common_antv.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/common/common_antv.ts @@ -33,10 +33,23 @@ import { PositionType } from '@antv/l7-core' import { centroid } from '@turf/centroid' import type { Plot } from '@antv/g2plot' import type { PickOptions } from '@antv/g2plot/lib/core/plot' -import { defaults } from 'lodash-es' +import { defaults, find } from 'lodash-es' import { useI18n } from '@/data-visualization/hooks/web/useI18n' -const { t: tI18n } = useI18n() import { isMobile } from '@/data-visualization/utils/utils' +import { GaodeMap, TMap, TencentMap } from '@antv/l7-maps' +import { + gaodeMapStyleOptions, + qqMapStyleOptions, + tdtMapStyleOptions +} from '@/data-visualization/chart/components/js/panel/charts/map/common' +import ChartCarouselTooltip, { + isPie, + isColumn, + isMix, + isSupport +} from '@/data-visualization/chart/components/js/g2plot_tooltip_carousel' + +const { t: tI18n } = useI18n() export function getPadding(chart: Chart): number[] { if (chart.drill) { @@ -137,14 +150,22 @@ export function getTheme(chart: Chart) { }, 'g2-tooltip-list-item': { display: 'flex', - 'align-items': 'center' + 'align-items': 'flex-start', + 'justify-content': 'space-between', + 'line-height': tooltipFontsize + 'px' }, 'g2-tooltip-name': { display: 'inline-block', - 'line-height': tooltipFontsize + 'px', - flex: 1 + 'line-height': tooltipFontsize + 'px' + }, + 'g2-tooltip-value': { + flex: 1, + display: 'inline-block', + 'text-align': 'end', + 'line-height': tooltipFontsize + 'px' }, 'g2-tooltip-marker': { + 'margin-top': (tooltipFontsize - 8) / 2 + 'px', 'min-width': '8px', 'min-height': '8px' } @@ -469,7 +490,8 @@ export function getXAxis(chart: Chart) { style: { fill: a.axisLabel.color, fontSize: a.axisLabel.fontSize, - textAlign: textAlign + textAlign: textAlign, + fontFamily: chart.fontFamily }, formatter: value => { return chart.type === 'bidirectional-bar' && value.length > a.axisLabel.lengthLimit @@ -574,7 +596,8 @@ export function getYAxis(chart: Chart) { fill: yAxis.axisLabel.color, fontSize: yAxis.axisLabel.fontSize, textBaseline, - textAlign + textAlign, + fontFamily: chart.fontFamily }, formatter: value => { return value.length > yAxis.axisLabel.lengthLimit @@ -603,7 +626,7 @@ export function getYAxisExt(chart: Chart) { return false } const title = - yAxis.name && yAxis.name !== '' + yAxis.nameShow && yAxis.name && yAxis.name !== '' ? { text: yAxis.name, style: { @@ -629,14 +652,16 @@ export function getYAxisExt(chart: Chart) { ? { style: { stroke: axisCfg.lineStyle.color, - lineWidth: axisCfg.lineStyle.width + lineWidth: axisCfg.lineStyle.width, + lineDash: getLineDash(axisCfg.lineStyle.style) } } : null const tickLine = axisCfg.show ? { style: { - stroke: axisCfg.lineStyle.color + stroke: axisCfg.lineStyle.color, + lineWidth: axisCfg.lineStyle.width } } : null @@ -673,7 +698,8 @@ export function getYAxisExt(chart: Chart) { fill: yAxis.axisLabel.color, fontSize: yAxis.axisLabel.fontSize, textBaseline, - textAlign + textAlign, + fontFamily: chart.fontFamily } } : null @@ -821,10 +847,9 @@ export function getAnalyseHorizontal(chart: Chart) { const assistLineArr = senior.assistLineCfg.assistLine if (assistLineArr?.length > 0) { const customStyle = parseJson(chart.customStyle) - let xAxisPosition, axisFormatterCfg + let axisFormatterCfg if (customStyle.xAxis) { const a = JSON.parse(JSON.stringify(customStyle.xAxis)) - xAxisPosition = transAxisPosition(a.position) axisFormatterCfg = a.axisLabelFormatter ? a.axisLabelFormatter : DEFAULT_XAXIS_STYLE.axisLabelFormatter @@ -894,7 +919,9 @@ export function getLineDash(type) { */ export function setGradientColor(rawColor: string, show = false, angle = 0, start = 0) { const item = rawColor.split(',') - item.splice(3, 1, '0.3)') + const alpha = parseFloat(item[3].replace(')', '')) + const startAlpha = alpha * 0.3 + item.splice(3, 1, `${startAlpha})`) let color: string if (start == 0) { color = `l(${angle}) 0:${item.join(',')} 1:${rawColor}` @@ -993,6 +1020,9 @@ export function configL7Tooltip(chart: Chart): TooltipOptions { return result } const head = originalItem.properties + if (!head) { + return result + } const formatter = formatterMap[head.quotaList?.[0]?.id] if (!isEmpty(formatter)) { const originValue = parseFloat(head.value as string) @@ -1152,13 +1182,27 @@ export class CustomZoom extends Zoom { 'l7-button-control', container, () => { - if (this.controlOption['bounds']) { - this.mapsService.fitBounds(this.controlOption['bounds'], { animate: true }) + if (this.mapsService.map?.deMapProvider == 'qq') { + if (this.mapsService.map.deMapAutoFit) { + this.mapsService.setZoomAndCenter(this.mapsService.map.deMapAutoZoom, [ + this.mapsService.map.deMapAutoLng, + this.mapsService.map.deMapAutoLat + ]) + } else { + this.mapsService.setZoomAndCenter( + this.controlOption['initZoom'], + this.controlOption['center'] + ) + } } else { - this.mapsService.setZoomAndCenter( - this.controlOption['initZoom'], - this.controlOption['center'] - ) + if (this.controlOption['bounds']) { + this.mapsService.fitBounds(this.controlOption['bounds'], { animate: true }) + } else { + this.mapsService.setZoomAndCenter( + this.controlOption['initZoom'], + this.controlOption['center'] + ) + } } } ) @@ -1208,7 +1252,11 @@ export class CustomZoom extends Zoom { } as IZoomControlOption } } -export function configL7Zoom(chart: Chart, scene: Scene) { +export function configL7Zoom( + chart: Chart, + scene: Scene, + mapKey?: { key: string; securityCode: string; mapType: string } +) { const { basicStyle } = parseJson(chart.customAttr) const zoomOption = scene?.getControlByName('zoom') if (zoomOption) { @@ -1220,20 +1268,56 @@ export function configL7Zoom(chart: Chart, scene: Scene) { if (!scene?.getControlByName('zoom')) { if (!scene.map) { scene.once('loaded', () => { - scene.map.on('complete', () => { - const initZoom = basicStyle.autoFit === false ? basicStyle.zoomLevel : scene.getZoom() - const center = - basicStyle.autoFit === false - ? [basicStyle.mapCenter.longitude, basicStyle.mapCenter.latitude] - : [scene.map.getCenter().lng, scene.map.getCenter().lat] - const newZoomOptions = { - initZoom: initZoom, - center: center, - buttonColor: basicStyle.zoomButtonColor, - buttonBackground: basicStyle.zoomBackground - } as any - scene.addControl(new CustomZoom(newZoomOptions)) - }) + switch (mapKey?.mapType) { + case 'tianditu': + //天地图 + { + const initZoom = basicStyle.autoFit === false ? basicStyle.zoomLevel : scene.getZoom() + const center = + basicStyle.autoFit === false + ? [basicStyle.mapCenter.longitude, basicStyle.mapCenter.latitude] + : [scene.map.getCenter().getLng(), scene.map.getCenter().getLat()] + const newZoomOptions = { + initZoom: initZoom, + center: center, + buttonColor: basicStyle.zoomButtonColor, + buttonBackground: basicStyle.zoomBackground + } as any + scene.addControl(new CustomZoom(newZoomOptions)) + } + break + case 'qq': + { + const initZoom = basicStyle.autoFit === false ? basicStyle.zoomLevel : scene.getZoom() + const center = + basicStyle.autoFit === false + ? [basicStyle.mapCenter.longitude, basicStyle.mapCenter.latitude] + : [scene.map.getCenter().lng, scene.map.getCenter().lat] + const newZoomOptions = { + initZoom: initZoom, + center: center, + buttonColor: basicStyle.zoomButtonColor, + buttonBackground: basicStyle.zoomBackground + } as any + scene.addControl(new CustomZoom(newZoomOptions)) + } + break + default: + scene.map.on('complete', () => { + const initZoom = basicStyle.autoFit === false ? basicStyle.zoomLevel : scene.getZoom() + const center = + basicStyle.autoFit === false + ? [basicStyle.mapCenter.longitude, basicStyle.mapCenter.latitude] + : [scene.map.getCenter().lng, scene.map.getCenter().lat] + const newZoomOptions = { + initZoom: initZoom, + center: center, + buttonColor: basicStyle.zoomButtonColor, + buttonBackground: basicStyle.zoomBackground + } as any + scene.addControl(new CustomZoom(newZoomOptions)) + }) + } }) } else { const newZoomOptions = { @@ -1250,19 +1334,19 @@ export function configL7Zoom(chart: Chart, scene: Scene) { const endAxis = chart.xAxisExt if (startAxis?.length === 2) { chart.data?.tableRow?.forEach(row => { - coordinates.push([row[startAxis[0].dataeaseName], row[startAxis[1].dataeaseName]]) + coordinates.push([row[startAxis[0].gisbiName], row[startAxis[1].gisbiName]]) }) } if (endAxis?.length === 2) { chart.data?.tableRow?.forEach(row => { - coordinates.push([row[endAxis[0].dataeaseName], row[endAxis[1].dataeaseName]]) + coordinates.push([row[endAxis[0].gisbiName], row[endAxis[1].gisbiName]]) }) } } else { const axis = chart.xAxis if (axis?.length === 2) { chart.data?.tableRow?.forEach(row => { - coordinates.push([row[axis[0].dataeaseName], row[axis[1].dataeaseName]]) + coordinates.push([row[axis[0].gisbiName], row[axis[1].gisbiName]]) }) } } @@ -1335,6 +1419,18 @@ export function mapRendering(dom: HTMLElement | string) { dom.classList.add('de-map-rendering') } +export function qqMapRendered(scene?: Scene) { + if (scene?.map && scene.map.deMapProvider === 'qq') { + setTimeout(() => { + if (scene.map) { + scene.map.deMapAutoZoom = scene.map.getZoom() + scene.map.deMapAutoLng = scene.map.getCenter().getLng() + scene.map.deMapAutoLat = scene.map.getCenter().getLat() + } + }, 1000) + } +} + export function mapRendered(dom: HTMLElement | string) { if (typeof dom === 'string') { dom = document.getElementById(dom) @@ -1342,6 +1438,213 @@ export function mapRendered(dom: HTMLElement | string) { dom.classList.add('de-map-rendered') } +export function getMapCenter(basicStyle: ChartBasicStyle) { + let center: [number, number] + if (basicStyle.autoFit === false) { + const longitude = basicStyle?.mapCenter?.longitude ?? DEFAULT_BASIC_STYLE.mapCenter.longitude + const latitude = basicStyle?.mapCenter?.latitude ?? DEFAULT_BASIC_STYLE.mapCenter.latitude + center = [longitude, latitude] + } else { + center = undefined + } + return center +} + +export function getMapStyle( + mapKey: { key: string; securityCode: string; mapType: string }, + basicStyle: ChartBasicStyle +) { + let mapStyle: string + switch (mapKey.mapType) { + case 'tianditu': + if (!find(tdtMapStyleOptions, s => s.value === basicStyle.mapStyle)) { + mapStyle = 'normal' + } else { + mapStyle = basicStyle.mapStyle + } + break + case 'qq': + if ( + !find(qqMapStyleOptions, s => s.value === basicStyle.mapStyle) || + basicStyle.mapStyle === 'normal' + ) { + mapStyle = 'normal' + } else { + mapStyle = basicStyle.mapStyleUrl + } + break + default: + if (!find(gaodeMapStyleOptions, s => s.value === basicStyle.mapStyle)) { + basicStyle.mapStyle = 'normal' + } + mapStyle = basicStyle.mapStyleUrl + if (basicStyle.mapStyle !== 'custom') { + mapStyle = `amap://styles/${basicStyle.mapStyle ? basicStyle.mapStyle : 'normal'}` + } + break + } + return mapStyle +} + +export async function getMapScene( + chart: Chart, + scene: Scene, + container: string, + mapKey: { key: string; securityCode: string; mapType: string }, + basicStyle: ChartBasicStyle, + miscStyle: ChartMiscAttr, + mapStyle: string, + center?: [number, number] +) { + if (!scene) { + scene = new Scene({ + id: container, + logoVisible: false, + map: getMapObject(mapKey, basicStyle, miscStyle, mapStyle, center) + }) + } else { + if (mapKey.mapType === 'tianditu') { + scene.map?.checkResize() + } + if (scene.getLayers()?.length) { + await scene.removeAllLayer() + try { + scene.setPitch(miscStyle.mapPitch) + } catch (e) {} + if (mapKey.mapType === 'tianditu') { + if (mapStyle === 'normal') { + scene.map?.removeStyle() + } else { + scene.setMapStyle(mapStyle) + } + } else { + scene.setMapStyle(mapStyle) + } + + scene.map.showLabel = !(basicStyle.showLabel === false) + if (mapKey.mapType === 'qq') { + scene.map.setBaseMap({ + //底图设置(参数为:VectorBaseMap对象) + type: 'vector', //类型:失量底图 + features: basicStyle.showLabel === false ? ['base', 'building2d'] : undefined + //仅渲染:道路及底面(base) + 2d建筑物(building2d),以达到隐藏文字的效果 + }) + } + } + if (basicStyle.autoFit === false) { + scene.setZoomAndCenter(basicStyle.zoomLevel, center) + if (mapKey.mapType === 'qq') { + scene.map.deMapAutoFit = false + scene.map.deMapZoom = basicStyle.zoomLevel + scene.map.deMapCenter = center + } + } + } + mapRendering(container) + scene.once('loaded', () => { + mapRendered(container) + if (mapKey.mapType === 'qq') { + scene.map.setBaseMap({ + //底图设置(参数为:VectorBaseMap对象) + type: 'vector', //类型:失量底图 + features: basicStyle.showLabel === false ? ['base', 'building2d'] : undefined + //仅渲染:道路及底面(base) + 2d建筑物(building2d),以达到隐藏文字的效果 + }) + scene.setMapStyle(mapStyle) + + scene.map.deMapProvider = 'qq' + scene.map.deMapAutoFit = !!basicStyle.autoFit + // scene.map.deMapAutoZoom = scene.map.getZoom() + // scene.map.deMapAutoLng = scene.map.getCenter().getLng() + // scene.map.deMapAutoLat = scene.map.getCenter().getLat() + } + // 去除天地图自己的缩放按钮 + if (mapKey.mapType === 'tianditu') { + if (mapStyle === 'normal') { + scene.map?.removeStyle() + } else { + scene.setMapStyle(mapStyle) + } + + const tdtControl = document.querySelector( + `#component${chart.id} .tdt-control-zoom.tdt-bar.tdt-control` + ) + if (tdtControl) { + tdtControl.style.display = 'none' + } + const tdtControlOuter = document.querySelectorAll( + `#wrapper-outer-id-${chart.id} .tdt-control-zoom.tdt-bar.tdt-control` + ) + if (tdtControlOuter && tdtControlOuter.length > 0) { + for (let i = 0; i < tdtControlOuter.length; i++) { + tdtControlOuter[i].style.display = 'none' + } + } + const tdtCopyrightControl = document.querySelector( + `#component${chart.id} .tdt-control-copyright.tdt-control` + ) + if (tdtCopyrightControl) { + tdtCopyrightControl.style.display = 'none' + } + const tdtCopyrightControlOuter = document.querySelectorAll( + `#wrapper-outer-id-${chart.id} .tdt-control-copyright.tdt-control` + ) + if (tdtCopyrightControlOuter && tdtCopyrightControlOuter.length > 0) { + for (let i = 0; i < tdtCopyrightControlOuter.length; i++) { + tdtCopyrightControlOuter[i].style.display = 'none' + } + } + } + }) + return scene +} + +export function getMapObject( + mapKey: { key: string; securityCode: string; mapType: string }, + basicStyle: ChartBasicStyle, + miscStyle: ChartMiscAttr, + mapStyle: string, + center?: [number, number] +) { + switch (mapKey.mapType) { + case 'tianditu': + return new TMap({ + token: mapKey?.key ?? undefined, + style: mapStyle, //不生效 + pitch: undefined, //不支持 + center, + zoom: basicStyle.autoFit === false ? basicStyle.zoomLevel : undefined, + showLabel: !(basicStyle.showLabel === false), //不支持 + WebGLParams: { + preserveDrawingBuffer: true + } + }) + case 'qq': + return new TencentMap({ + token: mapKey?.key ?? undefined, + style: mapStyle, + pitch: miscStyle.mapPitch, + center, + zoom: basicStyle.autoFit === false ? basicStyle.zoomLevel : 12, + showLabel: !(basicStyle.showLabel === false), + WebGLParams: { + preserveDrawingBuffer: true + } + }) + default: + return new GaodeMap({ + token: mapKey?.key ?? undefined, + style: mapStyle, + pitch: miscStyle.mapPitch, + center, + zoom: basicStyle.autoFit === false ? basicStyle.zoomLevel : undefined, + showLabel: !(basicStyle.showLabel === false), + WebGLParams: { + preserveDrawingBuffer: true + } + }) + } +} /** * 隐藏缩放控件 * @param basicStyle @@ -1358,6 +1661,8 @@ export function getTooltipContainer(id) { let wrapperDom = document.getElementById(G2_TOOLTIP_WRAPPER) if (!wrapperDom) { wrapperDom = document.createElement('div') + wrapperDom.style.position = 'absolute' + wrapperDom.style.zIndex = '9999' wrapperDom.id = G2_TOOLTIP_WRAPPER document.body.appendChild(wrapperDom) } @@ -1391,14 +1696,78 @@ export function getTooltipContainer(id) { } return g2Tooltip } + +/** + * 配置提示轮播 + * @param plot + * @param chart + */ +function configCarouselTooltip(plot, chart) { + const start = isSupport(chart.type) && !document.getElementById('multiplexingDrawer') + if (start) { + // 启用轮播 + plot.once('afterrender', () => { + const carousel = chart.customAttr?.tooltip?.carousel + ChartCarouselTooltip.manage(plot, chart, { + xField: 'field', + duration: carousel.enable ? carousel?.stayTime * 1000 : 2000, + interval: carousel.enable ? carousel?.intervalTime * 1000 : 2000 + }) + }) + } +} +/** + * 计算 Tooltip 的位置 + * @param {Chart} chart - 图表实例 + * @param {boolean} isCarousel - 是否为轮播模式 + * @param {object} tooltipCtl - Tooltip 控制器 + * @param {HTMLElement} chartElement - 图表元素 + * @param {Event} event - 事件对象 + * @param {boolean} enlargeElement - 放大弹窗 + * @returns {{x: number, y: number}} - 计算后的 x 和 y 坐标 + */ +function calculateTooltipPosition(chart, isCarousel, tooltipCtl, chartElement, event) { + // 辅助函数: 根据不同图表类型计算 Tooltip 的y位置 + const getTooltipY = () => { + const top = Number(chartElement.getBoundingClientRect().top) + if (isColumn(chart.type)) { + return top + chartElement.getBoundingClientRect().height / 2 + } + if (isMix(chart.type) || isPie(chart.type)) { + return top + tooltipCtl.point.y + } + return top + tooltipCtl.point.y + 60 + } + if (isCarousel) { + return { + x: tooltipCtl.point.x + Number(chartElement.getBoundingClientRect().left), + y: getTooltipY() + } + } else { + return { x: event.clientX, y: event.clientY } + } +} export function configPlotTooltipEvent>( chart: Chart, plot: P ) { const { tooltip } = parseJson(chart.customAttr) if (!tooltip.show) { + ChartCarouselTooltip.destroyByContainer(chart.container) return } + // 图表容器,用于计算 tooltip 的位置 + // 获取图表元素,优先顺序:放大 > 预览 > 公共连接页面 > 默认 + const chartElement = + document.getElementById('container-viewDialog-' + chart.id + '-common') || + document.getElementById('container-preview-' + chart.id + '-common') || + document.getElementById('enlarge-inner-content-' + chart.id) || + document.getElementById('shape-id-' + chart.id) + // 是否是放大弹窗 + const enlargeElement = chartElement?.id.includes('viewDialog') + // 轮播时tooltip的zIndex + const carousel_zIndex = enlargeElement ? '9999' : '1002' + configCarouselTooltip(plot, chart) // 鼠标可移入, 移入之后保持显示, 移出之后隐藏 plot.options.tooltip.container.addEventListener('mouseenter', e => { e.target.style.visibility = 'visible' @@ -1415,10 +1784,25 @@ export function configPlotTooltipEvent> if (!tooltipCtl) { return } + // 处理 tooltip 与下拉菜单的显示冲突问题 + const viewTrackBarElement = document.getElementById('view-track-bar-' + chart.id) const event = plot.chart.interactions.tooltip?.context?.event + // 是否时轮播模式 + const isCarousel = + chart.customAttr?.tooltip?.carousel && + (!event || // 事件触发时,使用event的client坐标 + ['plot:leave', 'plot:mouseleave'].includes(event?.type) || //鼠标离开时,使用tooltipCtl.point + ['pie', 'pie-rose', 'pie-donut'].includes(chart.type)) // 饼图时,使用tooltipCtl.point + plot.options.tooltip.showMarkers = isCarousel ? true : false + const wrapperDom = document.getElementById(G2_TOOLTIP_WRAPPER) + wrapperDom.style.zIndex = isCarousel && wrapperDom ? carousel_zIndex : '9999' if (tooltipCtl.tooltip) { // 处理视图放大后再关闭 tooltip 的 dom 被清除 const container = tooltipCtl.tooltip.cfg.container + // 当下拉菜单不显示时,移除tooltip的hidden-tooltip样式 + if (viewTrackBarElement?.getAttribute('aria-expanded') === 'false') { + container.classList.toggle('hidden-tooltip', false) + } container.style.display = 'block' const dom = document.getElementById(container.id) if (!dom) { @@ -1433,8 +1817,17 @@ export function configPlotTooltipEvent> } plot.chart.getOptions().tooltip.follow = false tooltipCtl.title = Math.random().toString() - plot.chart.getTheme().components.tooltip.x = event.clientX - plot.chart.getTheme().components.tooltip.y = event.clientY + // 当显示提示为事件触发时,使用event的client坐标,否则使用tooltipCtl.point 数据点的位置,在图表中,需要加上图表在绘制区的位置 + const { x, y } = calculateTooltipPosition( + chart, + isCarousel, + tooltipCtl, + chartElement, + event, + enlargeElement + ) + plot.chart.getTheme().components.tooltip.x = x + plot.chart.getTheme().components.tooltip.y = y }) // https://github.com/antvis/G2/blob/master/src/chart/controller/tooltip.ts#hideTooltip plot.on('plot:leave', () => { @@ -1457,14 +1850,22 @@ export function configPlotTooltipEvent> if (!tooltipCtl) { return } - const container = tooltipCtl.tooltip.cfg.container + const container = tooltipCtl.tooltip?.cfg.container for (const ele of wrapperDom.children) { - if (container.id !== ele.id) { + if (!container || container.id !== ele.id) { ele.style.display = 'none' } } } }) + plot.on('tooltip:hidden', () => { + const tooltipCtl = plot.chart.getController('tooltip') + if (!tooltipCtl) { + return + } + const container = tooltipCtl.tooltip?.cfg.container + container && (container.style.display = 'none') + }) } export const TOOLTIP_TPL = @@ -1699,10 +2100,12 @@ export function configYaxisTitleLengthLimit(chart, plot) { ? wrappedTitle.slice(0, wrappedTitle.length - 2) + '...' : wrappedTitle + '...' } - // 更新Y轴标题的原始文本和截断后的文本 - ev.view.options.axes.yAxisExt.title.originalText = yAxis.name - ev.view.options.axes.yAxisExt.title.text = wrappedTitle + const { title } = ev.view.options.axes.yAxisExt + if (title) { + title.originalText = yAxis.name + title.text = wrappedTitle + } }) } @@ -1731,7 +2134,7 @@ export const addConditionsStyleColorToData = (chart: Chart, options) => { }) } else if (item.quotaList?.length) { const quotaList = item.quotaList.map(q => q.id) ?? [] - quotaList.forEach((q, index) => { + quotaList.forEach(q => { // 定义后,在 handleConditionsStyle 函数中使用 let currentValue = item[valueField] if (chart.type === 'progress-bar') { @@ -1798,7 +2201,7 @@ const getColorByConditions = (quotaList: [], values: number | number[], chart) = * @param chart * @param options */ -export function handleConditionsStyle(chart: Chart, options: O) { +export function handleConditionsStyle(chart: Chart, options) { const { threshold } = parseJson(chart.senior) if (!threshold.enable) return options const { basicStyle } = parseJson(chart.customAttr) @@ -1810,8 +2213,6 @@ export function handleConditionsStyle(chart: Chart, options: O) { // 辅助函数:配置柱条样式颜色,条形图为barStyle,柱形图为columnStyle const columnStyle = data => { return { - ...options.columnStyle, - ...options.barStyle, ...(data[colorField]?.[0] ? { fill: data[colorField][0] } : {}) } } @@ -1825,8 +2226,8 @@ export function handleConditionsStyle(chart: Chart, options: O) { const tmpOption = { ...options, rawFields, - columnStyle: columnStyle, - barStyle: columnStyle, + ...configRoundAngle(chart, 'columnStyle', columnStyle), + ...configRoundAngle(chart, 'barStyle', columnStyle), tooltip: { ...options.tooltip, ...(options.tooltip['customItems'] @@ -1934,7 +2335,7 @@ export const getTooltipItemConditionColor = item => { * @param newData * @param container */ -export const configEmptyDataStyle = (newChart, newData, container) => { +export const configEmptyDataStyle = (newData, container, newChart?, content?) => { /** * 辅助函数:移除空数据dom */ @@ -1949,15 +2350,121 @@ export const configEmptyDataStyle = (newChart, newData, container) => { if (!newData.length) { const emptyDom = document.createElement('div') emptyDom.id = container + '_empty' - emptyDom.textContent = tI18n('data_set.no_data') + emptyDom.textContent = content || tI18n('data_set.no_data') emptyDom.setAttribute( 'style', `position: absolute; - left: 45%; - top: 50%;` + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + color: darkgray; + textAlign: center;` ) const parent = document.getElementById(container) parent.insertBefore(emptyDom, parent.firstChild) - newChart.destroy() + newChart?.destroy() + } +} + +export const numberToChineseUnderHundred = (num: number): string => { + // 合法性检查 + if (num <= 0 || num > 99 || !Number.isInteger(num)) { + throw new Error('请输入1-99之间的整数') + } + + const digits = ['', '一', '二', '三', '四', '五', '六', '七', '八', '九'] + + // 处理个位数 + if (num < 10) return digits[num] + + const tens = Math.floor(num / 10) + const ones = num % 10 + + // 处理整十 + if (ones === 0) { + return tens === 1 ? '十' : digits[tens] + '十' + } + + // 处理其他两位数 + return tens === 1 ? '十' + digits[ones] : digits[tens] + '十' + digits[ones] +} + +/** + * 配置柱条图的圆角 + * @param styleName + * @param callBack 自定义其他属性函数 + */ +export const configRoundAngle = (chart: Chart, styleName: string, callBack?: (datum) => {}) => { + const { basicStyle } = parseJson(chart.customAttr) + if (['roundAngle', 'topRoundAngle'].includes(basicStyle.radiusColumnBar)) { + const radius = Array(2).fill(basicStyle.columnBarRightAngleRadius) + const topRadius = [0, 0, ...radius] + const bottomRadius = [...radius, 0, 0] + const finalRadius = [...radius, ...radius] + if (chart.type.includes('-stack')) { + return { + [styleName]: datum => { + if (!datum.value) return { radius: [], ...(callBack ? callBack(datum) : {}) } + return { radius: finalRadius, ...(callBack ? callBack(datum) : {}) } + } + } + } + const isTopRound = basicStyle.radiusColumnBar === 'topRoundAngle' + // 对称条形图 + if (chart.type === 'bidirectional-bar') { + const valueField = basicStyle.layout === 'vertical' ? 'valueExt' : 'value' + return { + [styleName]: datum => ({ + radius: datum[valueField] && isTopRound ? topRadius : isTopRound ? radius : finalRadius, + ...(callBack ? callBack(datum) : {}) + }) + } + } + // 进度条 + if (chart.type === 'progress-bar') { + return { + [styleName]: datum => { + return { + radius: isTopRound ? bottomRadius : finalRadius, + ...(callBack ? callBack(datum) : {}) + } + } + } + } + // 区间条形图 + if (chart.type === 'bar-range') { + return { + [styleName]: datum => { + return { + radius: + datum?.values[0] < datum?.values[1] + ? isTopRound + ? bottomRadius + : finalRadius + : isTopRound + ? topRadius + : finalRadius, + ...(callBack ? callBack(datum) : {}) + } + } + } + } + // 配置柱条样式 + const style = datum => { + if (isTopRound) { + return { radius, ...(callBack ? callBack(datum) : {}) } + } + if (!isTopRound) { + return { radius: finalRadius, ...(callBack ? callBack(datum) : {}) } + } + } + return { + [styleName]: style + } + } + return { + [styleName]: datum => { + return { ...(callBack ? callBack(datum) : {}) } + } } } diff --git a/frontend/src/data-visualization/chart/components/js/panel/common/common_table.ts b/frontend/src/data-visualization/chart/components/js/panel/common/common_table.ts index 16fb754..2741b75 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/common/common_table.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/common/common_table.ts @@ -5,8 +5,10 @@ import { isAlphaColor, isTransparent, parseJson, - resetRgbOpacity -} from '../../util' + resetRgbOpacity, + safeDecimalSum, + safeDecimalMean +} from '../..//util' import { DEFAULT_BASIC_STYLE, DEFAULT_TABLE_CELL, @@ -43,13 +45,31 @@ import { updateShapeAttr, ViewMeta } from '@antv/s2' -import { cloneDeep, filter, find, intersection, keys, merge, repeat } from 'lodash-es' +import { + cloneDeep, + filter, + find, + intersection, + keys, + map, + maxBy, + meanBy, + merge, + minBy, + repeat, + sumBy, + size, + sum +} from 'lodash-es' import { createVNode, render } from 'vue' import TableTooltip from '@/data-visualization/chart/components/editor/common/TableTooltip.vue' import Exceljs from 'exceljs' import { saveAs } from 'file-saver' import { ElMessage } from 'element-plus-secondary' import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import Decimal from 'decimal.js' + + const { t: i18nt } = useI18n() export function getCustomTheme(chart: Chart): S2Theme { @@ -401,8 +421,7 @@ export function getCustomTheme(chart: Chart): S2Theme { }, dataCell: { cell: { - crossBackgroundColor: - enableTableCrossBG && !tableCell.mergeCells ? tableItemSubBgColor : tableItemBgColor, + crossBackgroundColor: enableTableCrossBG ? tableItemSubBgColor : tableItemBgColor, backgroundColor: tableItemBgColor }, bolderText: { @@ -504,8 +523,8 @@ export function getStyle(chart: Chart, dataConfig: S2DataConfig): Style { item => item.id === chart.drillFilters[0].fieldId ) const drillEnterField = xAxis[drillEnterFieldIndex] - fieldMap[curDrillField.dataeaseName] = { - width: fieldMap[drillEnterField.dataeaseName]?.width + fieldMap[curDrillField.gisbiName] = { + width: fieldMap[drillEnterField.gisbiName]?.width } } // 铺满 @@ -579,7 +598,7 @@ export function getCurrentField(valueFieldList: Axis[], field: ChartViewField) { if (list) { for (let i = 0; i < list.length; i++) { const f = list[i] - if (field.dataeaseName === f.dataeaseName) { + if (field.gisbiName === f.gisbiName) { res = f break } @@ -600,10 +619,10 @@ export function getConditions(chart: Chart) { } const conditions = threshold.tableThreshold ?? [] - const dimFields = [...chart.xAxis, ...chart.xAxisExt].map(i => i.dataeaseName) + const dimFields = [...chart.xAxis, ...chart.xAxisExt].map(i => i.gisbiName) if (conditions?.length > 0) { const { tableCell, basicStyle, tableHeader } = parseJson(chart.customAttr) - // 合并单元格时,班马纹失效 + // 合并单元格时斑马纹失效 const enableTableCrossBG = chart.type === 'table-info' ? tableCell.enableTableCrossBG && !tableCell.mergeCells @@ -626,12 +645,12 @@ export function getConditions(chart: Chart) { let defaultValueColor = valueColor let defaultBgColor = valueBgColor // 透视表表头颜色配置 - if (chart.type === 'table-pivot' && dimFields.includes(field.field.dataeaseName)) { + if (chart.type === 'table-pivot' && dimFields.includes(field.field.gisbiName)) { defaultValueColor = headerValueColor defaultBgColor = headerValueBgColor } res.text.push({ - field: field.field.dataeaseName, + field: field.field.gisbiName, mapping(value, rowData) { // 总计小计 if (rowData?.isTotals) { @@ -647,7 +666,7 @@ export function getConditions(chart: Chart) { } }) res.background.push({ - field: field.field.dataeaseName, + field: field.field.gisbiName, mapping(value, rowData) { if (rowData?.isTotals) { return null @@ -783,6 +802,9 @@ export function mappingColor(value, defaultColor, field, type, filedValueMap?, r } } else { // time + if (!tv || !value) { + break + } const fc = field.conditions[i] tv = new Date(tv.replace(/-/g, '/') + ' GMT+8').getTime() const v = new Date(value.replace(/-/g, '/') + ' GMT+8').getTime() @@ -842,7 +864,7 @@ function getFieldValueMap(view) { function getValue(field, filedValueMap, rowData) { if (field.summary === 'value') { - return rowData ? rowData[field.field?.dataeaseName] : undefined + return rowData ? rowData[field.field?.gisbiName] : undefined } else { return filedValueMap[field.summary + '-' + field.fieldId] } @@ -880,6 +902,7 @@ export function handleTableEmptyStrategy(chart: Chart) { } return newData } + export class SortTooltip extends BaseTooltip { show(showOptions) { const { iconName } = showOptions @@ -934,6 +957,7 @@ export class SortTooltip extends BaseTooltip { }) } } + const SORT_DEFAULT = '' const SORT_UP = @@ -1063,7 +1087,14 @@ export function copyContent(s2Instance: SpreadSheet, event, fieldMeta) { if (cells.length === 1) { const curCell = cells[0] if (cell.getMeta().id === curCell.id) { - copyString(cellMeta.value + '', true) + const cellMeta = cell.getMeta() + const value = cellMeta.data?.[cellMeta.valueField] + const metaObj = find(fieldMeta, m => m.field === cellMeta.valueField) + let fieldVal = value?.toString() + if (metaObj) { + fieldVal = metaObj.formatter(value) + } + copyString(fieldVal, true) } s2Instance.interaction.clearState() return @@ -1189,7 +1220,7 @@ export async function exportGridPivot(instance: PivotSheet, chart: ChartObj) { const { meta, fields } = instance.dataCfg const rowLength = fields?.rows?.length || 0 const colLength = fields?.columns?.length || 0 - const colNums = layoutResult.colLeafNodes.length + rowLength + 1 + const colNums = layoutResult.colLeafNodes.length + rowLength if (colNums > 16384) { ElMessage.warning(i18nt('chart.pivot_export_invalid_col_exceed')) return @@ -1346,9 +1377,180 @@ export async function exportGridPivot(instance: PivotSheet, chart: ChartObj) { if (fieldValue === 0 || fieldValue) { const meta = metaMap[dataCellMeta.valueField] const cell = worksheet.getCell(rowIndex + maxColHeight + 1, rowLength + colIndex + 1) - const value = meta?.formatter?.(fieldValue) || fieldValue.toString() + const value = meta?.formatter?.(fieldValue) || fieldValue cell.alignment = { vertical: 'middle', horizontal: 'center' } - cell.value = value + cell.value = isNumeric(value) ? parseFloat(value) : value + } + } + } + const buffer = await workbook.xlsx.writeBuffer() + const dataBlob = new Blob([buffer], { + type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8' + }) + saveAs(dataBlob, `${chart.title ?? '透视表'}.xlsx`) +} + +export async function exportRowQuotaGridPivot(instance: PivotSheet, chart: ChartObj) { + const { layoutResult } = instance.facet + const { meta, fields } = instance.dataCfg + const rowLength = fields?.rows?.length || 0 + const colLength = fields?.columns?.length || 0 + const colNums = layoutResult.colLeafNodes.length + rowLength + if (colNums > 16384) { + ElMessage.warning(i18nt('chart.pivot_export_invalid_col_exceed')) + return + } + const workbook = new Exceljs.Workbook() + const worksheet = workbook.addWorksheet(i18nt('chart.chart_data')) + const metaMap: Record = meta?.reduce((p, n) => { + if (n.field) { + p[n.field] = n + } + return p + }, {}) + // 角头 + if (colLength > 1) { + fields.columns.forEach((column: string, index) => { + if (index >= colLength - 1) { + return + } + const cell = worksheet.getCell(index + 1, 1) + cell.value = metaMap[column]?.name ?? column + cell.alignment = { vertical: 'middle', horizontal: 'center' } + cell.border = { + right: { style: 'thick', color: { argb: '00000000' } } + } + worksheet.mergeCells(index + 1, 1, index + 1, rowLength + 1) + }) + } + fields?.rows?.forEach((row, index) => { + const cell = worksheet.getCell(colLength === 0 ? 1 : colLength, index + 1) + cell.value = metaMap[row]?.name ?? row + cell.alignment = { vertical: 'middle', horizontal: 'center' } + cell.border = { bottom: { style: 'thick', color: { argb: '00000000' } } } + }) + const quotaColLabel = chart.customAttr.basicStyle.quotaColLabel ?? t('dataset.value') + const quotaColHeadCell = worksheet.getCell(colLength === 0 ? 1 : colLength, rowLength + 1) + quotaColHeadCell.value = quotaColLabel + quotaColHeadCell.alignment = { vertical: 'middle', horizontal: 'center' } + quotaColHeadCell.border = { + bottom: { style: 'thick', color: { argb: '00000000' } }, + right: { style: 'thick', color: { argb: '00000000' } } + } + // 行头 + const { rowLeafNodes, rowNodes } = layoutResult + const notLeafNodeHeightMap: Record = {} + rowLeafNodes.forEach(node => { + // 行头的高度由子节点相加决定,也就是行头子节点中包含的叶子节点数量 + let curNode = node.parent + while (curNode) { + const height = notLeafNodeHeightMap[curNode.id] ?? 0 + notLeafNodeHeightMap[curNode.id] = height + 1 + curNode = curNode.parent + } + const { rowIndex } = node + const writeRowIndex = rowIndex + 2 + (colLength === 0 ? 1 : colLength - 1) + const writeColIndex = node.level + 1 + const cell = worksheet.getCell(writeRowIndex, writeColIndex) + let value = node.label + if (node.field === '$$extra$$' && metaMap[value]?.name) { + value = metaMap[value].name + } + cell.value = value + cell.alignment = { vertical: 'middle', horizontal: 'center' } + cell.border = { + right: { style: 'thick', color: { argb: '00000000' } } + } + }) + + const getNodeStartRowIndex = (node: Node) => { + if (!node.children?.length) { + return node.rowIndex + 1 + } else { + return getNodeStartRowIndex(node.children[0]) + } + } + rowNodes?.forEach(node => { + if (node.isLeaf) { + return + } + const rowIndex = getNodeStartRowIndex(node) + const height = notLeafNodeHeightMap[node.id] + const writeRowIndex = rowIndex + 1 + (colLength === 0 ? 1 : colLength - 1) + const mergeColCount = node.children[0].level - node.level + const cell = worksheet.getCell(writeRowIndex, node.level + 1) + cell.value = node.label + cell.alignment = { vertical: 'middle', horizontal: 'center' } + if (mergeColCount > 1 || height > 1) { + worksheet.mergeCells( + writeRowIndex, + node.level + 1, + writeRowIndex + height - 1, + node.level + mergeColCount + ) + } + }) + + // 列头 + const { colLeafNodes, colNodes, colsHierarchy } = layoutResult + const maxColHeight = colsHierarchy.maxLevel + 1 + const notLeafNodeWidthMap: Record = {} + colLeafNodes.forEach(node => { + // 列头的宽度由子节点相加决定,也就是列头子节点中包含的叶子节点数量 + let curNode = node.parent + while (curNode) { + const width = notLeafNodeWidthMap[curNode.id] ?? 0 + notLeafNodeWidthMap[curNode.id] = width + 1 + curNode = curNode.parent + } + const { colIndex } = node + const writeRowIndex = node.level + 1 + const writeColIndex = colIndex + rowLength + 2 + const cell = worksheet.getCell(writeRowIndex, writeColIndex) + const value = node.label + cell.value = value + cell.alignment = { vertical: 'middle', horizontal: 'center' } + if (writeRowIndex < maxColHeight) { + worksheet.mergeCells(writeRowIndex, writeColIndex, maxColHeight, writeColIndex) + } + cell.border = { + bottom: { style: 'thick', color: { argb: '00000000' } } + } + }) + const getNodeStartColIndex = (node: Node) => { + if (!node.children?.length) { + return node.colIndex + 1 + } else { + return getNodeStartColIndex(node.children[0]) + } + } + colNodes.forEach(node => { + if (node.isLeaf) { + return + } + const colIndex = getNodeStartColIndex(node) + const width = notLeafNodeWidthMap[node.id] + const writeRowIndex = node.level + 1 + const value = node.label + const writeColIndex = colIndex + rowLength + 1 + const cell = worksheet.getCell(writeRowIndex, writeColIndex) + cell.value = value + cell.alignment = { vertical: 'middle', horizontal: 'center' } + if (width > 1) { + worksheet.mergeCells(writeRowIndex, writeColIndex, writeRowIndex, writeColIndex + width - 1) + } + }) + // 单元格数据 + for (let rowIndex = 0; rowIndex < rowLeafNodes.length; rowIndex++) { + for (let colIndex = 0; colIndex < colLeafNodes.length; colIndex++) { + const dataCellMeta = layoutResult.getCellMeta(rowIndex, colIndex) + const { fieldValue } = dataCellMeta + if (fieldValue === 0 || fieldValue) { + const meta = metaMap[dataCellMeta.valueField] + const cell = worksheet.getCell(rowIndex + maxColHeight + 1, rowLength + colIndex + 2) + const value = meta?.formatter?.(fieldValue) || fieldValue + cell.alignment = { vertical: 'middle', horizontal: 'center' } + cell.value = isNumeric(value) ? parseFloat(value) : value } } } @@ -1361,7 +1563,7 @@ export async function exportGridPivot(instance: PivotSheet, chart: ChartObj) { export async function exportTreePivot(instance: PivotSheet, chart: ChartObj) { const layoutResult = instance.facet.layoutResult - if (layoutResult.colLeafNodes.length + 2 > 16384) { + if (layoutResult.colLeafNodes.length + 1 > 16384) { ElMessage.warning(i18nt('chart.pivot_export_invalid_col_exceed')) return } @@ -1468,9 +1670,9 @@ export async function exportTreePivot(instance: PivotSheet, chart: ChartObj) { if (fieldValue === 0 || fieldValue) { const meta = metaMap[dataCellMeta.valueField] const cell = worksheet.getCell(rowIndex + maxColHeight + 1, colIndex + 1 + 1) - const value = meta?.formatter?.(fieldValue) || fieldValue.toString() + const value = meta?.formatter?.(fieldValue) || fieldValue cell.alignment = { vertical: 'middle', horizontal: 'center' } - cell.value = value + cell.value = isNumeric(value) ? parseFloat(value) : value } } } @@ -1480,6 +1682,135 @@ export async function exportTreePivot(instance: PivotSheet, chart: ChartObj) { }) saveAs(dataBlob, `${chart.title ?? '透视表'}.xlsx`) } + +export async function exportRowQuotaTreePivot(instance: PivotSheet, chart: ChartObj) { + const layoutResult = instance.facet.layoutResult + if (layoutResult.colLeafNodes.length + 1 > 16384) { + ElMessage.warning(i18nt('chart.pivot_export_invalid_col_exceed')) + return + } + const { meta, fields } = instance.dataCfg + const colLength = fields?.columns?.length || 0 + const workbook = new Exceljs.Workbook() + const worksheet = workbook.addWorksheet(i18nt('chart.chart_data')) + const metaMap: Record = meta?.reduce((p, n) => { + if (n.field) { + p[n.field] = n + } + return p + }, {}) + + // 角头 + fields.columns?.forEach((column, index) => { + if (index >= fields.columns.length - 1) { + return + } + const cell = worksheet.getCell(index + 1, 1) + cell.value = metaMap[column]?.name ?? column + cell.alignment = { vertical: 'middle', horizontal: 'center' } + cell.border = { + right: { style: 'thick', color: { argb: '00000000' } } + } + }) + const quotaColLabel = chart.customAttr.basicStyle.quotaColLabel ?? t('dataset.value') + const maxColHeight = layoutResult.colsHierarchy.maxLevel + 1 + const rowName = fields?.rows + ?.map(row => metaMap[row]?.name ?? row) + .concat(quotaColLabel) + .join('/') + const cell = worksheet.getCell(colLength, 1) + cell.value = rowName + cell.alignment = { vertical: 'middle', horizontal: 'center' } + cell.border = { + right: { style: 'thick', color: { argb: '00000000' } }, + bottom: { style: 'thick', color: { argb: '00000000' } } + } + //行头 + const { rowLeafNodes } = layoutResult + rowLeafNodes.forEach((node, index) => { + const cell = worksheet.getCell(maxColHeight + index + 1, 1) + let value = node.label + if (node.field === '$$extra$$' && metaMap[value]?.name) { + value = metaMap[value].name + } + cell.value = repeat(' ', node.level) + value + cell.alignment = { vertical: 'middle', horizontal: 'left' } + cell.border = { + right: { style: 'thick', color: { argb: '00000000' } } + } + }) + // 列头 + const notLeafNodeWidthMap: Record = {} + const { colLeafNodes } = layoutResult + colLeafNodes.forEach(node => { + let curNode = node.parent + while (curNode) { + const width = notLeafNodeWidthMap[curNode.id] ?? 0 + notLeafNodeWidthMap[curNode.id] = width + 1 + curNode = curNode.parent + } + const { colIndex } = node + const writeRowIndex = node.level + 1 + const writeColIndex = colIndex + 2 + const cell = worksheet.getCell(writeRowIndex, writeColIndex) + cell.value = node.label + cell.alignment = { vertical: 'middle', horizontal: 'center' } + if (writeRowIndex < maxColHeight) { + worksheet.mergeCells(writeRowIndex, writeColIndex, maxColHeight, writeColIndex) + } + cell.border = { + bottom: { style: 'thick', color: { argb: '00000000' } } + } + }) + const colNodes = layoutResult.colNodes + const getNodeStartIndex = (node: Node) => { + if (!node.children?.length) { + return node.colIndex + 1 + } else { + return getNodeStartIndex(node.children[0]) + } + } + colNodes.forEach(node => { + if (node.isLeaf) { + return + } + const colIndex = getNodeStartIndex(node) + const width = notLeafNodeWidthMap[node.id] + const writeRowIndex = node.level + 1 + const writeColIndex = colIndex + 1 + const cell = worksheet.getCell(writeRowIndex, writeColIndex) + cell.value = node.label + cell.alignment = { vertical: 'middle', horizontal: 'center' } + if (width > 1) { + worksheet.mergeCells(writeRowIndex, writeColIndex, writeRowIndex, writeColIndex + width - 1) + } + }) + // 单元格数据 + for (let rowIndex = 0; rowIndex < rowLeafNodes.length; rowIndex++) { + for (let colIndex = 0; colIndex < colLeafNodes.length; colIndex++) { + const dataCellMeta = layoutResult.getCellMeta(rowIndex, colIndex) + const { fieldValue } = dataCellMeta + if (fieldValue === 0 || fieldValue) { + const meta = metaMap[dataCellMeta.valueField] + const cell = worksheet.getCell(rowIndex + maxColHeight + 1, colIndex + 2) + const value = meta?.formatter?.(fieldValue) || fieldValue + cell.alignment = { vertical: 'middle', horizontal: 'center' } + cell.value = isNumeric(value) ? parseFloat(value) : value + } + } + } + const buffer = await workbook.xlsx.writeBuffer() + const dataBlob = new Blob([buffer], { + type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8' + }) + saveAs(dataBlob, `${chart.title ?? '透视表'}.xlsx`) +} + + +function isNumeric(value: string): boolean { + return /^[+-]?\d+(\.\d+)?$/.test(value) +} + export async function exportPivotExcel(instance: PivotSheet, chart: ChartObj) { const { fields } = instance.dataCfg const rowLength = fields?.rows?.length || 0 @@ -1488,10 +1819,19 @@ export async function exportPivotExcel(instance: PivotSheet, chart: ChartObj) { ElMessage.warning(i18nt('chart.pivot_export_invalid_field')) return } + const { quotaPosition } = chart.customAttr.basicStyle if (chart.customAttr.basicStyle.tableLayoutMode !== 'tree') { - exportGridPivot(instance, chart) + if (quotaPosition === 'row') { + exportRowQuotaGridPivot(instance, chart) + } else { + exportGridPivot(instance, chart) + } } else { - exportTreePivot(instance, chart) + if (quotaPosition === 'row') { + exportRowQuotaTreePivot(instance, chart) + } else { + exportTreePivot(instance, chart) + } } } @@ -1504,7 +1844,7 @@ export function configMergeCells(chart: Chart, options: S2Options, dataConfig: S const fields = chart.data.fields || [] const fieldsMap = fields.reduce((p, n) => { - p[n.dataeaseName] = n + p[n.gisbiName] = n return p }, {}) || {} const quotaIndex = dataConfig.meta.findIndex(m => fieldsMap[m.field]?.groupType === 'q') @@ -1571,6 +1911,7 @@ export function configMergeCells(chart: Chart, options: S2Options, dataConfig: S if (showIndex && meta.colIndex === 0) { meta.fieldValue = getRowIndex(mergedCellsInfo, meta) } + meta.deFieldType = fieldsMap[meta.valueField]?.deType return new CustomMergedCell(sheet, cells, meta) } } @@ -1598,12 +1939,13 @@ export function getRowIndex(mergedCellsInfo: MergedCellInfo[][], meta: ViewMeta) }, 0) return curRangeStartIndex - lostCells + 1 } + class CustomMergedCell extends MergedCell { protected drawBackgroundShape() { const allPoints = getPolygonPoints(this.cells) // 处理条件样式,这里没有用透明度 // 因为合并的单元格是单独的图层,透明度降低的话会显示底下未合并的单元格,需要单独处理被覆盖的单元格 - const { backgroundColor: fill, backgroundColorOpacity: fillOpacity } = this.getBackgroundColor() + const { backgroundColor: fill } = this.getBackgroundColor() const cellTheme = this.theme.dataCell.cell this.backgroundShape = renderPolygon(this, { points: allPoints, @@ -1612,6 +1954,14 @@ class CustomMergedCell extends MergedCell { lineHeight: cellTheme.horizontalBorderWidth }) } + + drawTextShape(): void { + if (this.meta.deFieldType === 7) { + drawImage.apply(this) + } else { + super.drawTextShape() + } + } } export class CustomDataCell extends TableDataCell { @@ -1847,96 +2197,95 @@ const getWrapTextHeight = (wrapText, textStyle, spreadsheet, maxLines) => { return Math.min(lines, maxLines) * maxHeight } -/** - * 设置汇总行 - * @param chart - * @param s2Options - * @param newData - * @param tableHeader - * @param basicStyle - * @param showSummary - */ -export const configSummaryRow = ( - chart, - s2Options, - newData, - tableHeader, - basicStyle, - showSummary -) => { - if (!showSummary || !newData.length) return - // 设置汇总行高度和表头一致 - const heightByField = {} - heightByField[newData.length] = tableHeader.tableTitleHeight - s2Options.style.rowCfg = { heightByField } - // 计算汇总加入到数据里,冻结最后一行 - s2Options.frozenTrailingRowCount = 1 - const yAxis = chart.yAxis - const xAxis = chart.xAxis - const summaryObj = newData.reduce( - (p, n) => { - if (chart.type === 'table-info') { - xAxis - .filter(axis => [2, 3, 4].includes(axis.deType)) - .forEach(axis => { - p[axis.dataeaseName] = - (parseFloat(n[axis.dataeaseName]) || 0) + (parseFloat(p[axis.dataeaseName]) || 0) +// 导出获取汇总行的函数 +export function getSummaryRow(data, axis, sumCon = []) { + const summaryObj = { SUMMARY: true } + for (let i = 0; i < axis.length; i++) { + const a = axis[i].gisbiName + let savedAxis = find(sumCon, s => s.field === a) + if (savedAxis) { + if (savedAxis.summary == undefined) { + savedAxis.summary = 'sum' // 默认汇总方式为求和 + } + if (savedAxis.show == undefined) { + savedAxis.show = true // 默认显示汇总结果 + } + } else { + savedAxis = { + field: a, + summary: 'sum', + show: true + } + } + // 如果配置为不显示,则跳过该字段 + if (!savedAxis.show) { + continue + } + // 根据汇总方式处理数据 + switch (savedAxis.summary) { + case 'sum': + // 计算字段的总和 + summaryObj[a] = safeDecimalSum(data, a) + break + case 'avg': + // 计算字段的平均值 + summaryObj[a] = safeDecimalMean(data, a) + break + case 'max': + // 计算字段的最大值 + summaryObj[a] = maxBy( + filter(data, d => parseFloat(d[a]) !== undefined), + d => parseFloat(d[a]) // 提取数值 + )[a] + break + case 'min': + // 计算字段的最小值 + summaryObj[a] = minBy( + filter(data, d => parseFloat(d[a]) !== undefined), + d => parseFloat(d[a]) // 提取数值 + )[a] + break + case 'var_pop': + // 计算总体方差(需要至少2个数据点) + if (data.length < 2) { + continue + } else { + const mean = safeDecimalMean(data, a) // 计算平均值 + // 计算每个数据点与平均值的差的平方 + const squaredDeviations = map(data, d => { + const value = new Decimal(d[a] ?? 0) // 获取字段值,如果不存在则使用0 + const dev = value.minus(mean) // 计算差值 + return dev.times(dev) // 计算平方 }) - } else { - yAxis.forEach(axis => { - p[axis.dataeaseName] = - (parseFloat(n[axis.dataeaseName]) || 0) + (parseFloat(p[axis.dataeaseName]) || 0) - }) - } - return p - }, - { SUMMARY: true } - ) - newData.push(summaryObj) - s2Options.dataCell = viewMeta => { - // 配置文本自动换行参数 - viewMeta.autoWrap = basicStyle.autoWrap - viewMeta.maxLines = basicStyle.maxLines - if (viewMeta.rowIndex !== newData.length - 1) { - return new CustomDataCell(viewMeta, viewMeta.spreadsheet) - } - if (viewMeta.colIndex === 0) { - if (tableHeader.showIndex) { - viewMeta.fieldValue = basicStyle.summaryLabel ?? i18nt('chart.total_show') - } else { - if (xAxis.length) { - viewMeta.fieldValue = basicStyle.summaryLabel ?? i18nt('chart.total_show') + // 计算方差(平方差的平均值) + const variance = squaredDeviations.reduce((acc, val) => acc.plus(val), new Decimal(0)) + summaryObj[a] = variance.dividedBy(data.length - 1).toNumber() // 计算总体方差 } - } + break + case 'stddev_pop': + // 计算总体标准差(需要至少2个数据点) + if (data.length < 2) { + continue + } else { + const mean = safeDecimalMean(data, a) // 计算平均值 + // 计算每个数据点与平均值的差的平方 + const squaredDeviations = map(data, d => { + const value = new Decimal(d[a] ?? 0) // 获取字段值,如果不存在则使用0 + const dev = value.minus(mean) // 计算差值 + return dev.times(dev) // 计算平方 + }) + // 计算方差(平方差的平均值) + const variance = squaredDeviations.reduce((acc, val) => acc.plus(val), new Decimal(0)) + summaryObj[a] = variance.dividedBy(data.length - 1).sqrt().toNumber() // 计算总体标准差 + } + break } - return new SummaryCell(viewMeta, viewMeta.spreadsheet) } + + // 返回汇总结果对象 + return summaryObj } -/** - * 汇总行样式,紧贴在单元格后面 - * @param newChart - * @param newData - * @param tableCell - * @param tableHeader - * @param showSummary - */ -export const summaryRowStyle = (newChart, newData, tableCell, tableHeader, showSummary) => { - if (!showSummary || !newData.length) return - newChart.on(S2Event.LAYOUT_BEFORE_RENDER, () => { - const showHeader = tableHeader.showTableHeader === true - // 不显示表头时,减少一个表头的高度 - const headerAndSummaryHeight = showHeader ? 2 : 1 - const totalHeight = - tableHeader.tableTitleHeight * headerAndSummaryHeight + - tableCell.tableItemHeight * (newData.length - 1) - if (totalHeight < newChart.options.height) { - // 6 是阴影高度 - newChart.options.height = - totalHeight < newChart.options.height - 6 ? totalHeight + 6 : totalHeight - } - }) -} export class SummaryCell extends CustomDataCell { getTextStyle() { @@ -1944,6 +2293,7 @@ export class SummaryCell extends CustomDataCell { textStyle.textAlign = this.theme.dataCell.text.textAlign return textStyle } + getBackgroundColor() { const { backgroundColor, backgroundColorOpacity } = this.theme.colCell.cell return { backgroundColor, backgroundColorOpacity } @@ -2019,3 +2369,27 @@ export const getColumns = (fields, cols: Array) => { } return result } + +export function drawImage() { + const img = new Image() + const { x, y, width, height, fieldValue } = this.meta + img.src = fieldValue as string + img.setAttribute('crossOrigin', 'anonymous') + img.onload = () => { + !this.cfg.children && (this.cfg.children = []) + const { width: imgWidth, height: imgHeight } = img + const ratio = Math.max(imgWidth / width, imgHeight / height) + // 不铺满,部分留白 + const imgShowWidth = (imgWidth / ratio) * 0.8 + const imgShowHeight = (imgHeight / ratio) * 0.8 + this.textShape = this.addShape('image', { + attrs: { + x: x + (imgShowWidth < width ? (width - imgShowWidth) / 2 : 0), + y: y + (imgShowHeight < height ? (height - imgShowHeight) / 2 : 0), + width: imgShowWidth, + height: imgShowHeight, + img + } + }) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/common/dist/common_antv.js b/frontend/src/data-visualization/chart/components/js/panel/common/dist/common_antv.js new file mode 100644 index 0000000..4b14a97 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/common/dist/common_antv.js @@ -0,0 +1,2404 @@ +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var __spreadArrays = (this && this.__spreadArrays) || function () { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; + for (var r = Array(s), k = 0, i = 0; i < il; i++) + for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) + r[k] = a[j]; + return r; +}; +exports.__esModule = true; +exports.configRoundAngle = exports.numberToChineseUnderHundred = exports.configEmptyDataStyle = exports.getTooltipItemConditionColor = exports.handleConditionsStyle = exports.addConditionsStyleColorToData = exports.configYaxisTitleLengthLimit = exports.configAxisLabelLengthLimit = exports.getConditions = exports.TOOLTIP_TPL = exports.configPlotTooltipEvent = exports.getTooltipContainer = exports.getMapObject = exports.getMapScene = exports.getMapStyle = exports.getMapCenter = exports.mapRendered = exports.qqMapRendered = exports.mapRendering = exports.configL7PlotZoom = exports.calculateBounds = exports.configL7Zoom = exports.CustomZoom = exports.configL7Legend = exports.getTooltipSeriesTotalMap = exports.handleGeoJson = exports.configL7Tooltip = exports.configL7Style = exports.configL7Label = exports.transAxisPosition = exports.setGradientColor = exports.getLineDash = exports.getAnalyseHorizontal = exports.getAnalyse = exports.getSlider = exports.getYAxisExt = exports.getYAxis = exports.getXAxis = exports.getLegend = exports.getMultiSeriesTooltip = exports.getTooltip = exports.getLabel = exports.getTheme = exports.getPadding = void 0; +var util_1 = require("../../util"); +var chart_1 = require("@/views/chart/components/editor/util/chart"); +var formatter_1 = require("@/views/chart/components/js/formatter"); +var mathjs_1 = require("mathjs"); +var isEmpty_1 = require("lodash-es/isEmpty"); +var lodash_1 = require("lodash"); +var create_dom_1 = require("@antv/dom-util/esm/create-dom"); +var constants_1 = require("@antv/l7plot-component/dist/esm/legend/category/constants"); +var substitute_1 = require("@antv/util/esm/substitute"); +var l7_1 = require("@antv/l7"); +var l7_utils_1 = require("@antv/l7-utils"); +var l7_scene_1 = require("@antv/l7-scene"); +var l7_core_1 = require("@antv/l7-core"); +var centroid_1 = require("@turf/centroid"); +var lodash_es_1 = require("lodash-es"); +var useI18n_1 = require("@/hooks/web/useI18n"); +var utils_1 = require("@/utils/utils"); +var l7_maps_1 = require("@antv/l7-maps"); +var common_1 = require("@/views/chart/components/js/panel/charts/map/common"); +var g2plot_tooltip_carousel_1 = require("@/views/chart/components/js/g2plot_tooltip_carousel"); +var tI18n = useI18n_1.useI18n().t; +function getPadding(chart) { + if (chart.drill) { + return [0, 10, 22, 10]; + } + else { + return [0, 10, 10, 10]; + } +} +exports.getPadding = getPadding; +// color,label,tooltip,axis,legend,background +function getTheme(chart) { + var colors = []; + var bgColor, labelFontsize, labelColor, tooltipColor, tooltipFontsize, tooltipBackgroundColor, legendColor, legendFontsize; + var customAttr; + if (chart.customAttr) { + customAttr = util_1.parseJson(chart.customAttr); + // color + if (customAttr.basicStyle) { + var b_1 = JSON.parse(JSON.stringify(customAttr.basicStyle)); + b_1.colors.forEach(function (ele) { + colors.push(util_1.hexColorToRGBA(ele, b_1.alpha)); + }); + } + // label + if (customAttr.label) { + var l = JSON.parse(JSON.stringify(customAttr.label)); + labelFontsize = l.fontSize; + labelColor = l.color; + } + // tooltip + if (customAttr.tooltip) { + var t = JSON.parse(JSON.stringify(customAttr.tooltip)); + tooltipColor = t.color; + tooltipFontsize = t.fontSize; + tooltipBackgroundColor = t.backgroundColor; + } + } + var customStyle; + if (chart.customStyle) { + customStyle = util_1.parseJson(chart.customStyle); + // bg + if (customStyle.background) { + bgColor = util_1.hexColorToRGBA(customStyle.background.color, customStyle.background.alpha); + } + // legend + if (customStyle.legend) { + var l = customStyle.legend; + legendColor = l.color; + legendFontsize = l.fontSize; + } + } + var theme = { + styleSheet: { + brandColor: colors[0], + paletteQualitative10: colors, + paletteQualitative20: colors, + backgroundColor: bgColor + }, + labels: { + offset: 4, + style: { + fill: labelColor, + fontSize: labelFontsize + } + }, + innerLabels: { + offset: 4, + style: { + fill: labelColor, + fontSize: labelFontsize + } + }, + pieLabels: { + offset: 4, + style: { + fill: labelColor, + fontSize: labelFontsize + } + }, + components: { + tooltip: { + domStyles: { + 'g2-tooltip': { + color: tooltipColor, + fontSize: tooltipFontsize + 'px', + background: tooltipBackgroundColor, + boxShadow: '0 4px 8px 0 rgba(0, 0, 0, 0.1)', + 'z-index': 2000, + position: 'fixed' + }, + 'g2-tooltip-list-item': { + display: 'flex', + 'align-items': 'flex-start', + 'justify-content': 'space-between', + 'line-height': tooltipFontsize + 'px' + }, + 'g2-tooltip-name': { + display: 'inline-block', + 'line-height': tooltipFontsize + 'px' + }, + 'g2-tooltip-value': { + flex: 1, + display: 'inline-block', + 'text-align': 'end', + 'line-height': tooltipFontsize + 'px' + }, + 'g2-tooltip-marker': { + 'margin-top': (tooltipFontsize - 8) / 2 + 'px', + 'min-width': '8px', + 'min-height': '8px' + } + } + }, + legend: { + common: { + itemName: { + style: { + fill: legendColor, + fontSize: legendFontsize + } + } + } + } + } + }; + if (chart.fontFamily) { + theme.styleSheet.fontFamily = chart.fontFamily; + } + return theme; +} +exports.getTheme = getTheme; +// 通用label +function getLabel(chart) { + var label; + var customAttr; + if (chart.customAttr) { + customAttr = util_1.parseJson(chart.customAttr); + // label + if (customAttr.label) { + var l_1 = customAttr.label; + if (l_1.show) { + var layout = []; + if (!l_1.fullDisplay) { + if (chart.type === 'bar-stack') { + layout.push({ type: 'interval-hide-overlap' }); + } + else if (chart.type.indexOf('-horizontal') > -1 || + [ + 'bidirectional-bar', + 'progress-bar', + 'pie-donut', + 'radar', + 'waterfall', + 't-heatmap', + 'bar' + ].includes(chart.type)) { + layout.push({ type: 'limit-in-canvas' }); + layout.push({ type: 'hide-overlap' }); + } + else if (chart.type.includes('chart-mix')) { + layout.push({ type: 'limit-in-canvas' }); + layout.push({ type: 'limit-in-plot' }); + layout.push({ type: 'hide-overlap' }); + } + else { + layout.push({ type: 'limit-in-plot' }); + layout.push({ type: 'hide-overlap' }); + } + } + label = { + position: l_1.position, + layout: layout, + style: { + fill: l_1.color, + fontSize: l_1.fontSize, + fontFamily: chart.fontFamily + }, + formatter: function (param) { + return formatter_1.valueFormatter(param.value, l_1.labelFormatter); + } + }; + } + else { + label = false; + } + } + } + return label; +} +exports.getLabel = getLabel; +// 通用tooltip +function getTooltip(chart) { + var tooltip; + var customAttr; + if (chart.customAttr) { + customAttr = util_1.parseJson(chart.customAttr); + // tooltip + if (customAttr.tooltip) { + var t_1 = JSON.parse(JSON.stringify(customAttr.tooltip)); + if (t_1.show) { + tooltip = { + formatter: function (param) { + var value = formatter_1.valueFormatter(param.value, t_1.tooltipFormatter); + return { name: param.field, value: value }; + }, + container: getTooltipContainer("tooltip-" + chart.id), + itemTpl: exports.TOOLTIP_TPL, + enterable: true + }; + } + else { + tooltip = false; + } + } + } + return tooltip; +} +exports.getTooltip = getTooltip; +function getMultiSeriesTooltip(chart) { + var _a; + var customAttr = util_1.parseJson(chart.customAttr); + var tooltipAttr = customAttr.tooltip; + if (!tooltipAttr.show) { + return false; + } + var formatterMap = (_a = tooltipAttr.seriesTooltipFormatter) === null || _a === void 0 ? void 0 : _a.filter(function (i) { return i.show; }).reduce(function (pre, next) { + pre[next.id] = next; + return pre; + }, {}); + var tooltip = { + showTitle: true, + customItems: function (originalItems) { + var _a, _b; + if (!((_a = tooltipAttr.seriesTooltipFormatter) === null || _a === void 0 ? void 0 : _a.length)) { + return originalItems; + } + var head = originalItems[0]; + // 非原始数据 + if (!head.data.quotaList) { + return originalItems; + } + var result = []; + originalItems + .filter(function (item) { return formatterMap[item.data.quotaList[0].id]; }) + .forEach(function (item) { + var formatter = formatterMap[item.data.quotaList[0].id]; + var value = formatter_1.valueFormatter(parseFloat(item.value), formatter.formatterCfg); + var name = isEmpty_1["default"](formatter.chartShowName) ? formatter.name : formatter.chartShowName; + var color = exports.getTooltipItemConditionColor(item); + result.push(__assign(__assign(__assign({}, item), { name: name, value: value }), (color ? { color: color } : {}))); + }); + (_b = head.data.dynamicTooltipValue) === null || _b === void 0 ? void 0 : _b.forEach(function (item) { + var formatter = formatterMap[item.fieldId]; + if (formatter) { + var value = formatter_1.valueFormatter(parseFloat(item.value), formatter.formatterCfg); + var name = isEmpty_1["default"](formatter.chartShowName) ? formatter.name : formatter.chartShowName; + result.push({ color: 'grey', name: name, value: value }); + } + }); + return result; + }, + container: getTooltipContainer("tooltip-" + chart.id), + itemTpl: exports.TOOLTIP_TPL, + enterable: true + }; + return tooltip; +} +exports.getMultiSeriesTooltip = getMultiSeriesTooltip; +// 通用legend +function getLegend(chart) { + var legend = {}; + var customStyle; + if (chart.customStyle) { + customStyle = util_1.parseJson(chart.customStyle); + // legend + if (customStyle.legend) { + var l = lodash_es_1.defaults(JSON.parse(JSON.stringify(customStyle.legend)), chart_1.DEFAULT_LEGEND_STYLE); + if (l.show) { + var offsetX = void 0, offsetY = void 0, position = void 0; + var orient = l.orient; + var legendSymbol = l.icon; + // fix position + if (l.hPosition === 'center') { + position = l.vPosition === 'center' ? 'top' : l.vPosition; + } + else if (l.vPosition === 'center') { + position = l.hPosition === 'center' ? 'left' : l.hPosition; + } + else { + if (orient === 'horizontal') { + position = l.vPosition + '-' + l.hPosition; + } + else { + position = l.hPosition + '-' + l.vPosition; + } + } + // fix offset + if (orient === 'horizontal') { + if (l.hPosition === 'left') { + offsetX = 16; + } + else if (l.hPosition === 'right') { + offsetX = -16; + } + else { + offsetX = 0; + } + if (l.vPosition === 'top') { + offsetY = 0; + } + else if (l.vPosition === 'bottom') { + if (chart.drill) { + offsetY = -12; + } + } + else { + offsetY = 0; + } + } + else { + if (l.hPosition === 'left') { + offsetX = 10; + } + else if (l.hPosition === 'right') { + offsetX = -10; + } + else { + offsetX = 0; + } + if (l.vPosition === 'top') { + offsetY = 0; + } + else if (l.vPosition === 'bottom') { + if (chart.drill) { + offsetY = -18; + } + else { + offsetY = -10; + } + } + else { + offsetY = 0; + } + } + legend = { + layout: orient, + position: position, + offsetX: offsetX, + offsetY: offsetY, + marker: { + symbol: legendSymbol, + style: { + r: l.size + } + }, + itemName: { + style: { + fill: l.color, + fontSize: l.fontSize + } + }, + itemHeight: (l.fontSize > l.size * 2 ? l.fontSize : l.size * 2) + 4, + radio: false, + pageNavigator: { + marker: { + style: { + fill: 'rgba(0,0,0,0.65)', + stroke: 'rgba(192,192,192,0.52)', + size: l.size * 2 + } + }, + text: { + style: { + fill: l.color, + fontSize: l.fontSize + } + } + } + }; + } + else { + legend = false; + } + } + } + return legend; +} +exports.getLegend = getLegend; +// xAxis +function getXAxis(chart) { + var axis = {}; + var customStyle; + if (chart.customStyle) { + customStyle = util_1.parseJson(chart.customStyle); + // legend + if (customStyle.xAxis) { + var a_1 = JSON.parse(JSON.stringify(customStyle.xAxis)); + if (a_1.show) { + var title = a_1.nameShow && a_1.name && a_1.name !== '' + ? { + text: a_1.name, + style: { + fill: a_1.color, + fontSize: a_1.fontSize + }, + spacing: 8 + } + : null; + var grid = a_1.splitLine.show + ? { + line: { + style: { + stroke: a_1.splitLine.lineStyle.color, + lineWidth: a_1.splitLine.lineStyle.width, + lineDash: getLineDash(a_1.splitLine.lineStyle.style) + } + } + } + : null; + var axisCfg = a_1.axisLine ? a_1.axisLine : chart_1.DEFAULT_XAXIS_STYLE.axisLine; + var line = axisCfg.show + ? { + style: { + stroke: axisCfg.lineStyle.color, + lineWidth: axisCfg.lineStyle.width, + lineDash: getLineDash(axisCfg.lineStyle.style) + } + } + : null; + var tickLine = axisCfg.show + ? { + style: { + stroke: axisCfg.lineStyle.color, + lineWidth: axisCfg.lineStyle.width + } + } + : null; + var textAlign = 'center'; + var rotate = a_1.axisLabel.rotate; + if (a_1.position === 'top') { + textAlign = rotate > 20 ? 'end' : rotate < -20 ? 'start' : 'center'; + } + if (a_1.position === 'bottom') { + textAlign = rotate > 20 ? 'start' : rotate < -20 ? 'end' : 'center'; + } + var label = a_1.axisLabel.show + ? { + rotate: (rotate * Math.PI) / 180, + style: { + fill: a_1.axisLabel.color, + fontSize: a_1.axisLabel.fontSize, + textAlign: textAlign, + fontFamily: chart.fontFamily + }, + formatter: function (value) { + return chart.type === 'bidirectional-bar' && value.length > a_1.axisLabel.lengthLimit + ? value.substring(0, a_1.axisLabel.lengthLimit) + '...' + : value; + } + } + : null; + axis = { + position: a_1.position, + title: title, + grid: grid, + label: label, + line: line, + tickLine: tickLine + }; + } + else { + axis = false; + } + } + } + return axis; +} +exports.getXAxis = getXAxis; +// yAxis +function getYAxis(chart) { + var axis = {}; + var yAxis = util_1.parseJson(chart.customStyle).yAxis; + if (!yAxis.show) { + return false; + } + var title = yAxis.nameShow && yAxis.name && yAxis.name !== '' + ? { + text: yAxis.name, + style: { + fill: yAxis.color, + fontSize: yAxis.fontSize + }, + spacing: 8 + } + : null; + var grid = yAxis.splitLine.show + ? { + line: { + style: { + stroke: yAxis.splitLine.lineStyle.color, + lineWidth: yAxis.splitLine.lineStyle.width, + lineDash: getLineDash(yAxis.splitLine.lineStyle.style) + } + } + } + : null; + var axisCfg = yAxis.axisLine ? yAxis.axisLine : chart_1.DEFAULT_YAXIS_STYLE.axisLine; + var line = axisCfg.show + ? { + style: { + stroke: axisCfg.lineStyle.color, + lineWidth: axisCfg.lineStyle.width, + lineDash: getLineDash(axisCfg.lineStyle.style) + } + } + : null; + var tickLine = axisCfg.show + ? { + style: { + stroke: axisCfg.lineStyle.color, + lineWidth: axisCfg.lineStyle.width + } + } + : null; + var rotate = yAxis.axisLabel.rotate; + var textAlign = 'end'; + var textBaseline = 'middle'; + if (yAxis.position === 'right') { + textAlign = 'start'; + if (Math.abs(rotate) > 75) { + textAlign = 'center'; + } + if (rotate > 75) { + textBaseline = 'bottom'; + } + if (rotate < -75) { + textBaseline = 'top'; + } + } + if (yAxis.position === 'left') { + if (Math.abs(rotate) > 75) { + textAlign = 'center'; + } + if (rotate > 75) { + textBaseline = 'top'; + } + if (rotate < -75) { + textBaseline = 'bottom'; + } + } + var label = yAxis.axisLabel.show + ? { + rotate: (rotate * Math.PI) / 180, + style: { + fill: yAxis.axisLabel.color, + fontSize: yAxis.axisLabel.fontSize, + textBaseline: textBaseline, + textAlign: textAlign, + fontFamily: chart.fontFamily + }, + formatter: function (value) { + return value.length > yAxis.axisLabel.lengthLimit + ? value.substring(0, yAxis.axisLabel.lengthLimit) + '...' + : value; + } + } + : null; + axis = { + position: yAxis.position, + title: title, + grid: grid, + label: label, + line: line, + tickLine: tickLine, + nice: true + }; + return axis; +} +exports.getYAxis = getYAxis; +function getYAxisExt(chart) { + var axis = {}; + var yAxis = util_1.parseJson(chart.customStyle).yAxisExt; + if (!yAxis.show) { + return false; + } + var title = yAxis.nameShow && yAxis.name && yAxis.name !== '' + ? { + text: yAxis.name, + style: { + fill: yAxis.color, + fontSize: yAxis.fontSize + }, + spacing: 8 + } + : null; + var grid = yAxis.splitLine.show + ? { + line: { + style: { + stroke: yAxis.splitLine.lineStyle.color, + lineWidth: yAxis.splitLine.lineStyle.width, + lineDash: getLineDash(yAxis.splitLine.lineStyle.style) + } + } + } + : null; + var axisCfg = yAxis.axisLine ? yAxis.axisLine : chart_1.DEFAULT_YAXIS_STYLE.axisLine; + var line = axisCfg.show + ? { + style: { + stroke: axisCfg.lineStyle.color, + lineWidth: axisCfg.lineStyle.width, + lineDash: getLineDash(axisCfg.lineStyle.style) + } + } + : null; + var tickLine = axisCfg.show + ? { + style: { + stroke: axisCfg.lineStyle.color, + lineWidth: axisCfg.lineStyle.width + } + } + : null; + var rotate = yAxis.axisLabel.rotate; + var textAlign = 'end'; + var textBaseline = 'middle'; + if (yAxis.position === 'right') { + textAlign = 'start'; + if (Math.abs(rotate) > 75) { + textAlign = 'center'; + } + if (rotate > 75) { + textBaseline = 'bottom'; + } + if (rotate < -75) { + textBaseline = 'top'; + } + } + if (yAxis.position === 'left') { + if (Math.abs(rotate) > 75) { + textAlign = 'center'; + } + if (rotate > 75) { + textBaseline = 'top'; + } + if (rotate < -75) { + textBaseline = 'bottom'; + } + } + var label = yAxis.axisLabel.show + ? { + rotate: (rotate * Math.PI) / 180, + style: { + fill: yAxis.axisLabel.color, + fontSize: yAxis.axisLabel.fontSize, + textBaseline: textBaseline, + textAlign: textAlign, + fontFamily: chart.fontFamily + } + } + : null; + axis = { + position: yAxis.position, + title: title, + grid: grid, + label: label, + line: line, + tickLine: tickLine, + nice: true + }; + return axis; +} +exports.getYAxisExt = getYAxisExt; +function getSlider(chart) { + var cfg; + var senior = util_1.parseJson(chart.senior); + if (senior.functionCfg) { + if (senior.functionCfg.sliderShow) { + cfg = { + start: senior.functionCfg.sliderRange[0] / 100, + end: senior.functionCfg.sliderRange[1] / 100 + }; + if (senior.functionCfg.sliderBg) { + cfg.backgroundStyle = { + fill: senior.functionCfg.sliderBg, + stroke: senior.functionCfg.sliderBg, + lineWidth: 1, + strokeOpacity: 0.5 + }; + } + if (senior.functionCfg.sliderFillBg) { + cfg.foregroundStyle = { + fill: senior.functionCfg.sliderFillBg, + fillOpacity: 0.5 + }; + } + if (senior.functionCfg.sliderTextColor) { + cfg.textStyle = { + fill: senior.functionCfg.sliderTextColor, + fontFamily: chart.fontFamily + }; + cfg.handlerStyle = { + fill: senior.functionCfg.sliderTextColor, + fillOpacity: 0.5, + highLightFill: senior.functionCfg.sliderTextColor + }; + } + } + } + return cfg; +} +exports.getSlider = getSlider; +function getAnalyse(chart) { + var _a, _b; + var assistLine = []; + var senior = util_1.parseJson(chart.senior); + if (!((_a = senior.assistLineCfg) === null || _a === void 0 ? void 0 : _a.enable)) { + return assistLine; + } + var assistLineArr = senior.assistLineCfg.assistLine; + if ((assistLineArr === null || assistLineArr === void 0 ? void 0 : assistLineArr.length) > 0) { + var customStyle = util_1.parseJson(chart.customStyle); + var yAxisPosition_1, axisFormatterCfg_1, yAxisExtPosition_1, axisExtFormatterCfg_1; + if (customStyle.yAxis) { + var a = JSON.parse(JSON.stringify(customStyle.yAxis)); + yAxisPosition_1 = a.position; + axisFormatterCfg_1 = a.axisLabelFormatter + ? a.axisLabelFormatter + : chart_1.DEFAULT_YAXIS_STYLE.axisLabelFormatter; + } + if (customStyle.yAxisExt) { + var a = JSON.parse(JSON.stringify(customStyle.yAxisExt)); + yAxisExtPosition_1 = a.position; + axisExtFormatterCfg_1 = a.axisLabelFormatter + ? a.axisLabelFormatter + : chart_1.DEFAULT_YAXIS_EXT_STYLE.axisLabelFormatter; + } + var fixedLines = assistLineArr.filter(function (ele) { return ele.field === '0'; }); + var dynamicLineFields_1 = assistLineArr + .filter(function (ele) { return ele.field === '1'; }) + .map(function (item) { return item.fieldId; }); + var quotaFields_1 = lodash_1["default"].filter(chart.yAxis, function (ele) { return ele.summary !== '' && ele.id !== '-1'; }); + var quotaExtFields_1 = lodash_1["default"].filter(chart.yAxisExt, function (ele) { return ele.summary !== '' && ele.id !== '-1'; }); + var dynamicLines = (_b = chart.data.dynamicAssistLines) === null || _b === void 0 ? void 0 : _b.filter(function (item) { + return ((dynamicLineFields_1 === null || dynamicLineFields_1 === void 0 ? void 0 : dynamicLineFields_1.includes(item.fieldId)) && + (!!lodash_1["default"].find(quotaFields_1, function (d) { return d.id === item.fieldId; }) || + (!!lodash_1["default"].find(quotaExtFields_1, function (d) { return d.id === item.fieldId; }) && + chart.type.includes('chart-mix')))); + }); + var lines = fixedLines.concat(dynamicLines || []); + lines.forEach(function (ele) { + var value = parseFloat(ele.value); + var content = ele.name + + ' : ' + + formatter_1.valueFormatter(value, ele.yAxisType === 'left' ? axisFormatterCfg_1 : axisExtFormatterCfg_1); + assistLine.push({ + type: 'line', + yAxisType: ele.yAxisType, + start: ['start', value], + end: ['end', value], + style: { + stroke: ele.color, + lineDash: getLineDash(ele.lineType) + } + }); + assistLine.push({ + type: 'text', + yAxisType: ele.yAxisType, + position: [ + (ele.yAxisType === 'left' ? yAxisPosition_1 : yAxisExtPosition_1) === 'left' + ? 'start' + : 'end', + value + ], + content: content, + offsetY: -2, + offsetX: (ele.yAxisType === 'left' ? yAxisPosition_1 : yAxisExtPosition_1) === 'left' + ? 2 + : -10 * (content.length - 2), + style: { + textBaseline: 'bottom', + fill: ele.color, + fontSize: ele.fontSize ? ele.fontSize : 10 + } + }); + }); + } + return assistLine; +} +exports.getAnalyse = getAnalyse; +function getAnalyseHorizontal(chart) { + var _a, _b; + var assistLine = []; + var senior = util_1.parseJson(chart.senior); + if (!((_a = senior.assistLineCfg) === null || _a === void 0 ? void 0 : _a.enable)) { + return assistLine; + } + var assistLineArr = senior.assistLineCfg.assistLine; + if ((assistLineArr === null || assistLineArr === void 0 ? void 0 : assistLineArr.length) > 0) { + var customStyle = util_1.parseJson(chart.customStyle); + var axisFormatterCfg_2; + if (customStyle.xAxis) { + var a = JSON.parse(JSON.stringify(customStyle.xAxis)); + axisFormatterCfg_2 = a.axisLabelFormatter + ? a.axisLabelFormatter + : chart_1.DEFAULT_XAXIS_STYLE.axisLabelFormatter; + } + var fixedLines = assistLineArr.filter(function (ele) { return ele.field === '0'; }); + var dynamicLineFields_2 = assistLineArr + .filter(function (ele) { return ele.field === '1'; }) + .map(function (item) { return item.fieldId; }); + var quotaFields_2 = lodash_1["default"].filter(chart.yAxis, function (ele) { return ele.summary !== '' && ele.id !== '-1'; }); + var dynamicLines = (_b = chart.data.dynamicAssistLines) === null || _b === void 0 ? void 0 : _b.filter(function (item) { + return (dynamicLineFields_2 === null || dynamicLineFields_2 === void 0 ? void 0 : dynamicLineFields_2.includes(item.fieldId)) && + !!lodash_1["default"].find(quotaFields_2, function (d) { return d.id === item.fieldId; }); + }); + var lines = fixedLines.concat(dynamicLines || []); + lines.forEach(function (ele) { + var value = parseFloat(ele.value); + var content = ele.name + ' : ' + formatter_1.valueFormatter(value, axisFormatterCfg_2); + assistLine.push({ + type: 'line', + start: ['start', value], + end: ['end', value], + style: { + stroke: ele.color, + lineDash: getLineDash(ele.lineType) + } + }); + assistLine.push({ + type: 'text', + position: ['start', value], + content: content, + offsetY: 5, + offsetX: 2, + rotate: Math.PI / 2, + style: { + textBaseline: 'bottom', + fill: ele.color, + fontSize: ele.fontSize ? ele.fontSize : 10 + } + }); + }); + } + return assistLine; +} +exports.getAnalyseHorizontal = getAnalyseHorizontal; +function getLineDash(type) { + switch (type) { + case 'solid': + return [0, 0]; + case 'dashed': + return [10, 8]; + case 'dotted': + return [2, 2]; + default: + return [0, 0]; + } +} +exports.getLineDash = getLineDash; +/** + * 将 RGBA 格式的颜色转换成 ANTV 支持的渐变色格式 + * @param rawColor 原始 RGBA 颜色 + * @param show + * @param angle 渐变角度 + * @param start 起始值 + */ +function setGradientColor(rawColor, show, angle, start) { + if (show === void 0) { show = false; } + if (angle === void 0) { angle = 0; } + if (start === void 0) { start = 0; } + var item = rawColor.split(','); + var alpha = parseFloat(item[3].replace(')', '')); + var startAlpha = alpha * 0.3; + item.splice(3, 1, startAlpha + ")"); + var color; + if (start == 0) { + color = "l(" + angle + ") 0:" + item.join(',') + " 1:" + rawColor; + } + else if (start > 0) { + color = "l(" + angle + ") 0:rgba(255,255,255,0) " + start + ":" + item.join(',') + " 1:" + rawColor; + } + else { + color = "l(" + angle + ") 0:rgba(255,255,255,0) 0.1:" + item.join(',') + " 1:" + rawColor; + } + return show ? color : rawColor; +} +exports.setGradientColor = setGradientColor; +function transAxisPosition(position) { + switch (position) { + case 'top': + return 'left'; + case 'bottom': + return 'right'; + case 'left': + return 'bottom'; + case 'right': + return 'top'; + default: + return position; + } +} +exports.transAxisPosition = transAxisPosition; +function configL7Label(chart) { + var customAttr = util_1.parseJson(chart.customAttr); + var label = customAttr.label; + var style = { + fill: label.color, + fontSize: label.fontSize, + textAllowOverlap: true, + fontWeight: 'bold' + }; + if (!label.fullDisplay) { + style.textAllowOverlap = false; + style.padding = [2, 2]; + } + if (chart.fontFamily) { + style.fontFamily = chart.fontFamily; + } + return { + visible: label.show, + style: style + }; +} +exports.configL7Label = configL7Label; +function configL7Style(chart) { + var customAttr = util_1.parseJson(chart.customAttr); + return { + stroke: customAttr.basicStyle.areaBorderColor + }; +} +exports.configL7Style = configL7Style; +function configL7Tooltip(chart) { + var _a; + var customAttr = util_1.parseJson(chart.customAttr); + var tooltip = customAttr.tooltip; + var formatterMap = (_a = tooltip.seriesTooltipFormatter) === null || _a === void 0 ? void 0 : _a.filter(function (i) { return i.show; }).reduce(function (pre, next) { + pre[next.id] = next; + return pre; + }, {}); + var container = document.getElementById(chart.container); + if (container) { + container.addEventListener('mousemove', function (event) { + var rect = container.getBoundingClientRect(); + var mouseX = event.clientX - rect.left; + var mouseY = event.clientY - rect.top; + var tooltipElement = container.getElementsByClassName('l7plot-tooltip-container'); + for (var i = 0; i < (tooltipElement === null || tooltipElement === void 0 ? void 0 : tooltipElement.length); i++) { + var element = tooltipElement[i]; + var isNearRightEdge = container.clientWidth - mouseX <= element.clientWidth; + var isNearBottomEdge = container.clientHeight - mouseY <= element.clientHeight; + var transform = ''; + if (isNearRightEdge) { + transform += 'translateX(-120%) '; + } + if (isNearBottomEdge) { + transform += 'translateY(-100%) '; + } + if (transform) { + element.style.transform = transform.trim(); + } + } + }); + } + return { + customTitle: function (data) { + return data.name; + }, + customItems: function (originalItem) { + var _a, _b, _c; + var result = []; + if (isEmpty_1["default"](formatterMap)) { + return result; + } + var head = originalItem.properties; + if (!head) { + return result; + } + var formatter = formatterMap[(_b = (_a = head.quotaList) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.id]; + if (!isEmpty_1["default"](formatter)) { + var originValue = parseFloat(head.value); + var value = formatter_1.valueFormatter(originValue, formatter.formatterCfg); + var name = isEmpty_1["default"](formatter.chartShowName) ? formatter.name : formatter.chartShowName; + result.push(__assign(__assign({}, head), { name: name, value: "" + (value !== null && value !== void 0 ? value : '') })); + } + (_c = head.dynamicTooltipValue) === null || _c === void 0 ? void 0 : _c.forEach(function (item) { + var formatter = formatterMap[item.fieldId]; + if (formatter) { + var value = formatter_1.valueFormatter(parseFloat(item.value), formatter.formatterCfg); + var name = isEmpty_1["default"](formatter.chartShowName) ? formatter.name : formatter.chartShowName; + result.push({ color: 'grey', name: name, value: "" + (value !== null && value !== void 0 ? value : '') }); + } + }); + return result; + }, + showComponent: tooltip.show, + domStyles: { + 'l7plot-tooltip': { + 'background-color': tooltip.backgroundColor, + 'font-size': tooltip.fontSize + "px", + 'line-height': 1.6, + 'font-family': chart.fontFamily ? chart.fontFamily : undefined + }, + 'l7plot-tooltip__name': { + color: tooltip.color + }, + 'l7plot-tooltip__value': { + color: tooltip.color + }, + 'l7plot-tooltip__title': { + color: tooltip.color + } + } + }; +} +exports.configL7Tooltip = configL7Tooltip; +function handleGeoJson(geoJson, nameMapping) { + geoJson.features.forEach(function (item) { + if (!item.properties['centroid']) { + if (item.properties['center']) { + item.properties['centroid'] = item.properties['center']; + } + else { + var tmp = centroid_1.centroid(item.geometry); + item.properties['centroid'] = tmp.geometry.coordinates; + } + } + var name = item.properties['name']; + if (nameMapping === null || nameMapping === void 0 ? void 0 : nameMapping[name]) { + name = nameMapping[name]; + item.properties['name'] = name; + } + }); +} +exports.handleGeoJson = handleGeoJson; +function getTooltipSeriesTotalMap(data) { + var result = {}; + data === null || data === void 0 ? void 0 : data.forEach(function (item) { + var _a; + (_a = item.dynamicTooltipValue) === null || _a === void 0 ? void 0 : _a.forEach(function (ele) { + if (!result[ele.fieldId]) { + result[ele.fieldId] = 0; + } + if (ele.value) { + result[ele.fieldId] = mathjs_1.add(result[ele.fieldId], ele.value); + } + }); + }); + return result; +} +exports.getTooltipSeriesTotalMap = getTooltipSeriesTotalMap; +var LEGEND_SHAPE_STYLE_MAP = { + circle: { + borderRadius: '50%' + }, + square: {}, + triangle: { + borderLeft: '5px solid transparent', + borderRight: '5px solid transparent', + borderBottom: '10px solid var(--bgColor)', + background: 'unset' + }, + diamond: { + transform: 'rotate(45deg)' + } +}; +function configL7Legend(chart) { + var basicStyle = util_1.parseJson(chart.customAttr).basicStyle; + if (basicStyle.suspension === false && basicStyle.showZoom === undefined) { + return false; + } + var legend = util_1.parseJson(chart.customStyle).legend; + if (!legend.show) { + return false; + } + return { + position: 'bottomleft', + customContent: function (_, items) { + var showItems = (items === null || items === void 0 ? void 0 : items.length) > 30 ? items.slice(0, 30) : items; + if (showItems === null || showItems === void 0 ? void 0 : showItems.length) { + var containerDom = create_dom_1["default"](constants_1.CONTAINER_TPL); + var listDom_1 = containerDom.getElementsByClassName(constants_1.LIST_CLASS)[0]; + showItems.forEach(function (item) { + var value = '-'; + if (item.value !== '') { + if (Array.isArray(item.value)) { + item.value.forEach(function (v, i) { + item.value[i] = Number.isNaN(v) || v === 'NaN' ? 'NaN' : parseFloat(v).toFixed(0); + }); + value = item.value.join('-'); + } + else { + var tmp = item.value; + value = Number.isNaN(tmp) || tmp === 'NaN' ? 'NaN' : parseFloat(tmp).toFixed(0); + } + } + var substituteObj = __assign(__assign({}, item), { value: value }); + var domStr = substitute_1["default"](constants_1.ITEM_TPL, substituteObj); + var itemDom = create_dom_1["default"](domStr); + // 给 legend 形状用的 + itemDom.style.setProperty('--bgColor', item.color); + listDom_1.appendChild(itemDom); + }); + return listDom_1; + } + return ''; + }, + domStyles: { + 'l7plot-legend__category-value': { + fontSize: legend.fontSize + 'px', + color: legend.color + }, + 'l7plot-legend__category-marker': __assign({}, LEGEND_SHAPE_STYLE_MAP[legend.icon]) + } + }; +} +exports.configL7Legend = configL7Legend; +var ZOOM_IN_BTN = ''; +var RESET_BTN = ''; +var ZOOM_OUT_BTN = ''; +var CustomZoom = /** @class */ (function (_super) { + __extends(CustomZoom, _super); + function CustomZoom() { + return _super !== null && _super.apply(this, arguments) || this; + } + CustomZoom.prototype.resetButtonGroup = function (container) { + var _this = this; + l7_utils_1.DOM.clearChildren(container); + this['zoomInButton'] = this['createButton'](this.controlOption.zoomInText, this.controlOption.zoomInTitle, 'l7-button-control', container, this.zoomIn); + this['zoomResetButton'] = this['createButton'](this.controlOption['resetText'], 'Reset', 'l7-button-control', container, function () { + var _a; + if (((_a = _this.mapsService.map) === null || _a === void 0 ? void 0 : _a.deMapProvider) == 'qq') { + if (_this.mapsService.map.deMapAutoFit) { + _this.mapsService.setZoomAndCenter(_this.mapsService.map.deMapAutoZoom, [ + _this.mapsService.map.deMapAutoLng, + _this.mapsService.map.deMapAutoLat + ]); + } + else { + _this.mapsService.setZoomAndCenter(_this.controlOption['initZoom'], _this.controlOption['center']); + } + } + else { + if (_this.controlOption['bounds']) { + _this.mapsService.fitBounds(_this.controlOption['bounds'], { animate: true }); + } + else { + _this.mapsService.setZoomAndCenter(_this.controlOption['initZoom'], _this.controlOption['center']); + } + } + }); + if (this.controlOption.showZoom) { + this['zoomNumDiv'] = this['createButton']('0', '', 'l7-button-control l7-control-zoom__number', container); + } + this['zoomOutButton'] = this['createButton'](this.controlOption.zoomOutText, this.controlOption.zoomOutTitle, 'l7-button-control', container, this.zoomOut); + var buttonBackground = this.controlOption.buttonBackground; + var elements = [this['zoomResetButton'], this['zoomInButton'], this['zoomOutButton']]; + if (buttonBackground) { + setStyle(elements, 'background', buttonBackground); + } + setStyle(elements, 'border-bottom', 'none'); + this['updateDisabled'](); + }; + CustomZoom.prototype.getDefault = function (option) { + var buttonColor = option.buttonColor; + var zoomInText = ZOOM_IN_BTN; + var zoomOutText = ZOOM_OUT_BTN; + var resetText = RESET_BTN; + if (buttonColor) { + zoomInText = zoomInText.replace('${fill}', buttonColor); + zoomOutText = zoomOutText.replace('${fill}', buttonColor); + resetText = resetText.replace('${fill}', buttonColor); + } + return __assign(__assign({}, option), { position: l7_core_1.PositionType.BOTTOMRIGHT, name: 'zoom', zoomInText: zoomInText, zoomInTitle: 'Zoom in', zoomOutText: zoomOutText, zoomOutTitle: 'Zoom out', resetText: resetText, showZoom: false }); + }; + return CustomZoom; +}(l7_1.Zoom)); +exports.CustomZoom = CustomZoom; +function configL7Zoom(chart, scene, mapKey) { + var _a, _b, _c, _d, _e, _f; + var basicStyle = util_1.parseJson(chart.customAttr).basicStyle; + var zoomOption = scene === null || scene === void 0 ? void 0 : scene.getControlByName('zoom'); + if (zoomOption) { + scene.removeControl(zoomOption); + } + if (shouldHideZoom(basicStyle)) { + return; + } + if (!(scene === null || scene === void 0 ? void 0 : scene.getControlByName('zoom'))) { + if (!scene.map) { + scene.once('loaded', function () { + switch (mapKey === null || mapKey === void 0 ? void 0 : mapKey.mapType) { + case 'tianditu': + //天地图 + { + var initZoom = basicStyle.autoFit === false ? basicStyle.zoomLevel : scene.getZoom(); + var center = basicStyle.autoFit === false + ? [basicStyle.mapCenter.longitude, basicStyle.mapCenter.latitude] + : [scene.map.getCenter().getLng(), scene.map.getCenter().getLat()]; + var newZoomOptions = { + initZoom: initZoom, + center: center, + buttonColor: basicStyle.zoomButtonColor, + buttonBackground: basicStyle.zoomBackground + }; + scene.addControl(new CustomZoom(newZoomOptions)); + } + break; + case 'qq': + { + var initZoom = basicStyle.autoFit === false ? basicStyle.zoomLevel : scene.getZoom(); + var center = basicStyle.autoFit === false + ? [basicStyle.mapCenter.longitude, basicStyle.mapCenter.latitude] + : [scene.map.getCenter().lng, scene.map.getCenter().lat]; + var newZoomOptions = { + initZoom: initZoom, + center: center, + buttonColor: basicStyle.zoomButtonColor, + buttonBackground: basicStyle.zoomBackground + }; + scene.addControl(new CustomZoom(newZoomOptions)); + } + break; + default: + scene.map.on('complete', function () { + var initZoom = basicStyle.autoFit === false ? basicStyle.zoomLevel : scene.getZoom(); + var center = basicStyle.autoFit === false + ? [basicStyle.mapCenter.longitude, basicStyle.mapCenter.latitude] + : [scene.map.getCenter().lng, scene.map.getCenter().lat]; + var newZoomOptions = { + initZoom: initZoom, + center: center, + buttonColor: basicStyle.zoomButtonColor, + buttonBackground: basicStyle.zoomBackground + }; + scene.addControl(new CustomZoom(newZoomOptions)); + }); + } + }); + } + else { + var newZoomOptions = { + buttonColor: basicStyle.zoomButtonColor, + buttonBackground: basicStyle.zoomBackground + }; + if (basicStyle.autoFit === false) { + newZoomOptions.initZoom = basicStyle.zoomLevel; + newZoomOptions.center = [basicStyle.mapCenter.longitude, basicStyle.mapCenter.latitude]; + } + else { + var coordinates_1 = []; + if (chart.type === 'flow-map') { + var startAxis_1 = chart.xAxis; + var endAxis_1 = chart.xAxisExt; + if ((startAxis_1 === null || startAxis_1 === void 0 ? void 0 : startAxis_1.length) === 2) { + (_b = (_a = chart.data) === null || _a === void 0 ? void 0 : _a.tableRow) === null || _b === void 0 ? void 0 : _b.forEach(function (row) { + coordinates_1.push([row[startAxis_1[0].gisbiName], row[startAxis_1[1].gisbiName]]); + }); + } + if ((endAxis_1 === null || endAxis_1 === void 0 ? void 0 : endAxis_1.length) === 2) { + (_d = (_c = chart.data) === null || _c === void 0 ? void 0 : _c.tableRow) === null || _d === void 0 ? void 0 : _d.forEach(function (row) { + coordinates_1.push([row[endAxis_1[0].gisbiName], row[endAxis_1[1].gisbiName]]); + }); + } + } + else { + var axis_1 = chart.xAxis; + if ((axis_1 === null || axis_1 === void 0 ? void 0 : axis_1.length) === 2) { + (_f = (_e = chart.data) === null || _e === void 0 ? void 0 : _e.tableRow) === null || _f === void 0 ? void 0 : _f.forEach(function (row) { + coordinates_1.push([row[axis_1[0].gisbiName], row[axis_1[1].gisbiName]]); + }); + } + } + newZoomOptions.bounds = calculateBounds(coordinates_1); + } + scene.addControl(new CustomZoom(newZoomOptions)); + } + } +} +exports.configL7Zoom = configL7Zoom; +/** + * 计算经纬度数据的边界点 + * @param coordinates 经纬度数组 [[lng, lat], [lng, lat], ...] + * @returns {[[number, number], [number, number]]} 返回东北角和西南角的坐标 + */ +function calculateBounds(coordinates) { + if (!coordinates || coordinates.length === 0) { + return { + northEast: [180, 90], + southWest: [-180, -90] + }; + } + var maxLng = -180; + var minLng = 180; + var maxLat = -90; + var minLat = 90; + coordinates.forEach(function (_a) { + var lng = _a[0], lat = _a[1]; + maxLng = Math.max(maxLng, lng); + minLng = Math.min(minLng, lng); + maxLat = Math.max(maxLat, lat); + minLat = Math.min(minLat, lat); + }); + return [ + [maxLng, maxLat], + [minLng, minLat] // 西南角坐标 + ]; +} +exports.calculateBounds = calculateBounds; +function configL7PlotZoom(chart, plot) { + var basicStyle = util_1.parseJson(chart.customAttr).basicStyle; + if (shouldHideZoom(basicStyle)) { + return; + } + plot.once('loaded', function () { + var zoomOptions = { + initZoom: plot.scene.getZoom(), + center: plot.scene.getCenter(), + buttonColor: basicStyle.zoomButtonColor, + buttonBackground: basicStyle.zoomBackground + }; + plot.scene.addControl(new CustomZoom(zoomOptions)); + }); +} +exports.configL7PlotZoom = configL7PlotZoom; +function setStyle(elements, styleProp, value) { + elements.forEach(function (e) { + e.style[styleProp] = value; + }); +} +function mapRendering(dom) { + if (typeof dom === 'string') { + dom = document.getElementById(dom); + } + dom.classList.add('de-map-rendering'); +} +exports.mapRendering = mapRendering; +function qqMapRendered(scene) { + if ((scene === null || scene === void 0 ? void 0 : scene.map) && scene.map.deMapProvider === 'qq') { + setTimeout(function () { + if (scene.map) { + scene.map.deMapAutoZoom = scene.map.getZoom(); + scene.map.deMapAutoLng = scene.map.getCenter().getLng(); + scene.map.deMapAutoLat = scene.map.getCenter().getLat(); + } + }, 1000); + } +} +exports.qqMapRendered = qqMapRendered; +function mapRendered(dom) { + if (typeof dom === 'string') { + dom = document.getElementById(dom); + } + dom.classList.add('de-map-rendered'); +} +exports.mapRendered = mapRendered; +function getMapCenter(basicStyle) { + var _a, _b, _c, _d; + var center; + if (basicStyle.autoFit === false) { + var longitude = (_b = (_a = basicStyle === null || basicStyle === void 0 ? void 0 : basicStyle.mapCenter) === null || _a === void 0 ? void 0 : _a.longitude) !== null && _b !== void 0 ? _b : chart_1.DEFAULT_BASIC_STYLE.mapCenter.longitude; + var latitude = (_d = (_c = basicStyle === null || basicStyle === void 0 ? void 0 : basicStyle.mapCenter) === null || _c === void 0 ? void 0 : _c.latitude) !== null && _d !== void 0 ? _d : chart_1.DEFAULT_BASIC_STYLE.mapCenter.latitude; + center = [longitude, latitude]; + } + else { + center = undefined; + } + return center; +} +exports.getMapCenter = getMapCenter; +function getMapStyle(mapKey, basicStyle) { + var mapStyle; + switch (mapKey.mapType) { + case 'tianditu': + if (!lodash_es_1.find(common_1.tdtMapStyleOptions, function (s) { return s.value === basicStyle.mapStyle; })) { + mapStyle = 'normal'; + } + else { + mapStyle = basicStyle.mapStyle; + } + break; + case 'qq': + if (!lodash_es_1.find(common_1.qqMapStyleOptions, function (s) { return s.value === basicStyle.mapStyle; }) || + basicStyle.mapStyle === 'normal') { + mapStyle = 'normal'; + } + else { + mapStyle = basicStyle.mapStyleUrl; + } + break; + default: + if (!lodash_es_1.find(common_1.gaodeMapStyleOptions, function (s) { return s.value === basicStyle.mapStyle; })) { + basicStyle.mapStyle = 'normal'; + } + mapStyle = basicStyle.mapStyleUrl; + if (basicStyle.mapStyle !== 'custom') { + mapStyle = "amap://styles/" + (basicStyle.mapStyle ? basicStyle.mapStyle : 'normal'); + } + break; + } + return mapStyle; +} +exports.getMapStyle = getMapStyle; +function getMapScene(chart, scene, container, mapKey, basicStyle, miscStyle, mapStyle, center) { + var _a, _b, _c; + return __awaiter(this, void 0, void 0, function () { + return __generator(this, function (_d) { + switch (_d.label) { + case 0: + if (!!scene) return [3 /*break*/, 1]; + scene = new l7_scene_1.Scene({ + id: container, + logoVisible: false, + map: getMapObject(mapKey, basicStyle, miscStyle, mapStyle, center) + }); + return [3 /*break*/, 4]; + case 1: + if (mapKey.mapType === 'tianditu') { + (_a = scene.map) === null || _a === void 0 ? void 0 : _a.checkResize(); + } + if (!((_b = scene.getLayers()) === null || _b === void 0 ? void 0 : _b.length)) return [3 /*break*/, 3]; + return [4 /*yield*/, scene.removeAllLayer()]; + case 2: + _d.sent(); + try { + scene.setPitch(miscStyle.mapPitch); + } + catch (e) { } + if (mapKey.mapType === 'tianditu') { + if (mapStyle === 'normal') { + (_c = scene.map) === null || _c === void 0 ? void 0 : _c.removeStyle(); + } + else { + scene.setMapStyle(mapStyle); + } + } + else { + scene.setMapStyle(mapStyle); + } + scene.map.showLabel = !(basicStyle.showLabel === false); + if (mapKey.mapType === 'qq') { + scene.map.setBaseMap({ + //底图设置(参数为:VectorBaseMap对象) + type: 'vector', + features: basicStyle.showLabel === false ? ['base', 'building2d'] : undefined + //仅渲染:道路及底面(base) + 2d建筑物(building2d),以达到隐藏文字的效果 + }); + } + _d.label = 3; + case 3: + if (basicStyle.autoFit === false) { + scene.setZoomAndCenter(basicStyle.zoomLevel, center); + if (mapKey.mapType === 'qq') { + scene.map.deMapAutoFit = false; + scene.map.deMapZoom = basicStyle.zoomLevel; + scene.map.deMapCenter = center; + } + } + _d.label = 4; + case 4: + mapRendering(container); + scene.once('loaded', function () { + var _a; + mapRendered(container); + if (mapKey.mapType === 'qq') { + scene.map.setBaseMap({ + //底图设置(参数为:VectorBaseMap对象) + type: 'vector', + features: basicStyle.showLabel === false ? ['base', 'building2d'] : undefined + //仅渲染:道路及底面(base) + 2d建筑物(building2d),以达到隐藏文字的效果 + }); + scene.setMapStyle(mapStyle); + scene.map.deMapProvider = 'qq'; + scene.map.deMapAutoFit = !!basicStyle.autoFit; + // scene.map.deMapAutoZoom = scene.map.getZoom() + // scene.map.deMapAutoLng = scene.map.getCenter().getLng() + // scene.map.deMapAutoLat = scene.map.getCenter().getLat() + } + // 去除天地图自己的缩放按钮 + if (mapKey.mapType === 'tianditu') { + if (mapStyle === 'normal') { + (_a = scene.map) === null || _a === void 0 ? void 0 : _a.removeStyle(); + } + else { + scene.setMapStyle(mapStyle); + } + var tdtControl = document.querySelector("#component" + chart.id + " .tdt-control-zoom.tdt-bar.tdt-control"); + if (tdtControl) { + tdtControl.style.display = 'none'; + } + var tdtControlOuter = document.querySelectorAll("#wrapper-outer-id-" + chart.id + " .tdt-control-zoom.tdt-bar.tdt-control"); + if (tdtControlOuter && tdtControlOuter.length > 0) { + for (var i = 0; i < tdtControlOuter.length; i++) { + tdtControlOuter[i].style.display = 'none'; + } + } + var tdtCopyrightControl = document.querySelector("#component" + chart.id + " .tdt-control-copyright.tdt-control"); + if (tdtCopyrightControl) { + tdtCopyrightControl.style.display = 'none'; + } + var tdtCopyrightControlOuter = document.querySelectorAll("#wrapper-outer-id-" + chart.id + " .tdt-control-copyright.tdt-control"); + if (tdtCopyrightControlOuter && tdtCopyrightControlOuter.length > 0) { + for (var i = 0; i < tdtCopyrightControlOuter.length; i++) { + tdtCopyrightControlOuter[i].style.display = 'none'; + } + } + } + }); + return [2 /*return*/, scene]; + } + }); + }); +} +exports.getMapScene = getMapScene; +function getMapObject(mapKey, basicStyle, miscStyle, mapStyle, center) { + var _a, _b, _c; + switch (mapKey.mapType) { + case 'tianditu': + return new l7_maps_1.TMap({ + token: (_a = mapKey === null || mapKey === void 0 ? void 0 : mapKey.key) !== null && _a !== void 0 ? _a : undefined, + style: mapStyle, + pitch: undefined, + center: center, + zoom: basicStyle.autoFit === false ? basicStyle.zoomLevel : undefined, + showLabel: !(basicStyle.showLabel === false), + WebGLParams: { + preserveDrawingBuffer: true + } + }); + case 'qq': + return new l7_maps_1.TencentMap({ + token: (_b = mapKey === null || mapKey === void 0 ? void 0 : mapKey.key) !== null && _b !== void 0 ? _b : undefined, + style: mapStyle, + pitch: miscStyle.mapPitch, + center: center, + zoom: basicStyle.autoFit === false ? basicStyle.zoomLevel : 12, + showLabel: !(basicStyle.showLabel === false), + WebGLParams: { + preserveDrawingBuffer: true + } + }); + default: + return new l7_maps_1.GaodeMap({ + token: (_c = mapKey === null || mapKey === void 0 ? void 0 : mapKey.key) !== null && _c !== void 0 ? _c : undefined, + style: mapStyle, + pitch: miscStyle.mapPitch, + center: center, + zoom: basicStyle.autoFit === false ? basicStyle.zoomLevel : undefined, + showLabel: !(basicStyle.showLabel === false), + WebGLParams: { + preserveDrawingBuffer: true + } + }); + } +} +exports.getMapObject = getMapObject; +/** + * 隐藏缩放控件 + * @param basicStyle + */ +function shouldHideZoom(basicStyle) { + return ((basicStyle.suspension === false && basicStyle.showZoom === undefined) || + basicStyle.showZoom === false); +} +var G2_TOOLTIP_WRAPPER = 'g2-tooltip-wrapper'; +function getTooltipContainer(id) { + var wrapperDom = document.getElementById(G2_TOOLTIP_WRAPPER); + if (!wrapperDom) { + wrapperDom = document.createElement('div'); + wrapperDom.style.position = 'absolute'; + wrapperDom.style.zIndex = '9999'; + wrapperDom.id = G2_TOOLTIP_WRAPPER; + document.body.appendChild(wrapperDom); + } + var curDom = document.getElementById(id); + if (curDom) { + curDom.remove(); + } + var g2Tooltip = document.createElement('div'); + g2Tooltip.setAttribute('id', id); + g2Tooltip.classList.add('g2-tooltip'); + // 最多半屏,鼠标移入可滚动 + g2Tooltip.style.maxHeight = '50%'; + utils_1.isMobile() ? (g2Tooltip.style.maxWidth = '50%') : (g2Tooltip.style.maxWidth = '25%'); + g2Tooltip.style.overflowY = 'auto'; + g2Tooltip.style.display = 'none'; + g2Tooltip.style.position = 'fixed'; + g2Tooltip.style.left = '0px'; + g2Tooltip.style.top = '0px'; + var g2TooltipTitle = document.createElement('div'); + g2TooltipTitle.classList.add('g2-tooltip-title'); + g2Tooltip.appendChild(g2TooltipTitle); + var g2TooltipList = document.createElement('ul'); + g2TooltipList.classList.add('g2-tooltip-list'); + g2Tooltip.appendChild(g2TooltipList); + var full = document.getElementsByClassName('fullscreen'); + if (full.length) { + full.item(0).appendChild(g2Tooltip); + } + else { + wrapperDom.appendChild(g2Tooltip); + } + return g2Tooltip; +} +exports.getTooltipContainer = getTooltipContainer; +/** + * 配置提示轮播 + * @param plot + * @param chart + */ +function configCarouselTooltip(plot, chart) { + var start = g2plot_tooltip_carousel_1.isSupport(chart.type) && !document.getElementById('multiplexingDrawer'); + if (start) { + // 启用轮播 + plot.once('afterrender', function () { + var _a, _b; + var carousel = (_b = (_a = chart.customAttr) === null || _a === void 0 ? void 0 : _a.tooltip) === null || _b === void 0 ? void 0 : _b.carousel; + g2plot_tooltip_carousel_1["default"].manage(plot, chart, { + xField: 'field', + duration: carousel.enable ? (carousel === null || carousel === void 0 ? void 0 : carousel.stayTime) * 1000 : 2000, + interval: carousel.enable ? (carousel === null || carousel === void 0 ? void 0 : carousel.intervalTime) * 1000 : 2000 + }); + }); + } +} +/** + * 计算 Tooltip 的位置 + * @param {Chart} chart - 图表实例 + * @param {boolean} isCarousel - 是否为轮播模式 + * @param {object} tooltipCtl - Tooltip 控制器 + * @param {HTMLElement} chartElement - 图表元素 + * @param {Event} event - 事件对象 + * @param {boolean} enlargeElement - 放大弹窗 + * @returns {{x: number, y: number}} - 计算后的 x 和 y 坐标 + */ +function calculateTooltipPosition(chart, isCarousel, tooltipCtl, chartElement, event) { + // 辅助函数: 根据不同图表类型计算 Tooltip 的y位置 + var getTooltipY = function () { + var top = Number(chartElement.getBoundingClientRect().top); + if (g2plot_tooltip_carousel_1.isColumn(chart.type)) { + return top + chartElement.getBoundingClientRect().height / 2; + } + if (g2plot_tooltip_carousel_1.isMix(chart.type) || g2plot_tooltip_carousel_1.isPie(chart.type)) { + return top + tooltipCtl.point.y; + } + return top + tooltipCtl.point.y + 60; + }; + if (isCarousel) { + return { + x: tooltipCtl.point.x + Number(chartElement.getBoundingClientRect().left), + y: getTooltipY() + }; + } + else { + return { x: event.clientX, y: event.clientY }; + } +} +function configPlotTooltipEvent(chart, plot) { + var tooltip = util_1.parseJson(chart.customAttr).tooltip; + if (!tooltip.show) { + g2plot_tooltip_carousel_1["default"].destroyByContainer(chart.container); + return; + } + // 图表容器,用于计算 tooltip 的位置 + // 获取图表元素,优先顺序:放大 > 预览 > 公共连接页面 > 默认 + var chartElement = document.getElementById('container-viewDialog-' + chart.id + '-common') || + document.getElementById('container-preview-' + chart.id + '-common') || + document.getElementById('enlarge-inner-content-' + chart.id) || + document.getElementById('shape-id-' + chart.id); + // 是否是放大弹窗 + var enlargeElement = chartElement === null || chartElement === void 0 ? void 0 : chartElement.id.includes('viewDialog'); + // 轮播时tooltip的zIndex + var carousel_zIndex = enlargeElement ? '9999' : '1002'; + configCarouselTooltip(plot, chart); + // 鼠标可移入, 移入之后保持显示, 移出之后隐藏 + plot.options.tooltip.container.addEventListener('mouseenter', function (e) { + e.target.style.visibility = 'visible'; + e.target.style.display = 'block'; + }); + plot.options.tooltip.container.addEventListener('mouseleave', function (e) { + e.target.style.visibility = 'hidden'; + e.target.style.display = 'none'; + }); + // 手动处理 tooltip 的显示和隐藏事件,需配合源码理解 + // https://github.com/antvis/G2/blob/master/src/chart/controller/tooltip.ts#showTooltip + plot.on('tooltip:show', function () { + var _a, _b, _c, _d; + var tooltipCtl = plot.chart.getController('tooltip'); + if (!tooltipCtl) { + return; + } + // 处理 tooltip 与下拉菜单的显示冲突问题 + var viewTrackBarElement = document.getElementById('view-track-bar-' + chart.id); + var event = (_b = (_a = plot.chart.interactions.tooltip) === null || _a === void 0 ? void 0 : _a.context) === null || _b === void 0 ? void 0 : _b.event; + // 是否时轮播模式 + var isCarousel = ((_d = (_c = chart.customAttr) === null || _c === void 0 ? void 0 : _c.tooltip) === null || _d === void 0 ? void 0 : _d.carousel) && + (!event || // 事件触发时,使用event的client坐标 + ['plot:leave', 'plot:mouseleave'].includes(event === null || event === void 0 ? void 0 : event.type) || //鼠标离开时,使用tooltipCtl.point + ['pie', 'pie-rose', 'pie-donut'].includes(chart.type)); // 饼图时,使用tooltipCtl.point + plot.options.tooltip.showMarkers = isCarousel ? true : false; + var wrapperDom = document.getElementById(G2_TOOLTIP_WRAPPER); + wrapperDom.style.zIndex = isCarousel && wrapperDom ? carousel_zIndex : '9999'; + if (tooltipCtl.tooltip) { + // 处理视图放大后再关闭 tooltip 的 dom 被清除 + var container = tooltipCtl.tooltip.cfg.container; + // 当下拉菜单不显示时,移除tooltip的hidden-tooltip样式 + if ((viewTrackBarElement === null || viewTrackBarElement === void 0 ? void 0 : viewTrackBarElement.getAttribute('aria-expanded')) === 'false') { + container.classList.toggle('hidden-tooltip', false); + } + container.style.display = 'block'; + var dom = document.getElementById(container.id); + if (!dom) { + var full = document.getElementsByClassName('fullscreen'); + if (full.length) { + full.item(0).appendChild(container); + } + else { + var wrapperDom_1 = document.getElementById(G2_TOOLTIP_WRAPPER); + wrapperDom_1.appendChild(container); + } + } + } + plot.chart.getOptions().tooltip.follow = false; + tooltipCtl.title = Math.random().toString(); + // 当显示提示为事件触发时,使用event的client坐标,否则使用tooltipCtl.point 数据点的位置,在图表中,需要加上图表在绘制区的位置 + var _e = calculateTooltipPosition(chart, isCarousel, tooltipCtl, chartElement, event, enlargeElement), x = _e.x, y = _e.y; + plot.chart.getTheme().components.tooltip.x = x; + plot.chart.getTheme().components.tooltip.y = y; + }); + // https://github.com/antvis/G2/blob/master/src/chart/controller/tooltip.ts#hideTooltip + plot.on('plot:leave', function () { + var _a, _b; + var tooltipCtl = plot.chart.getController('tooltip'); + if (!tooltipCtl) { + return; + } + plot.chart.getOptions().tooltip.follow = true; + var container = (_b = (_a = tooltipCtl.tooltip) === null || _a === void 0 ? void 0 : _a.cfg) === null || _b === void 0 ? void 0 : _b.container; + if (container) { + container.style.display = 'none'; + } + tooltipCtl.hideTooltip(); + }); + // 移动端处理,关闭其他图表的提示 + plot.on('plot:touchstart', function () { + var _a; + var wrapperDom = document.getElementById(G2_TOOLTIP_WRAPPER); + if (wrapperDom) { + var tooltipCtl = plot.chart.getController('tooltip'); + if (!tooltipCtl) { + return; + } + var container = (_a = tooltipCtl.tooltip) === null || _a === void 0 ? void 0 : _a.cfg.container; + for (var _i = 0, _b = wrapperDom.children; _i < _b.length; _i++) { + var ele = _b[_i]; + if (!container || container.id !== ele.id) { + ele.style.display = 'none'; + } + } + } + }); + plot.on('tooltip:hidden', function () { + var _a; + var tooltipCtl = plot.chart.getController('tooltip'); + if (!tooltipCtl) { + return; + } + var container = (_a = tooltipCtl.tooltip) === null || _a === void 0 ? void 0 : _a.cfg.container; + container && (container.style.display = 'none'); + }); +} +exports.configPlotTooltipEvent = configPlotTooltipEvent; +exports.TOOLTIP_TPL = '
  • ' + + '' + + '{name}:' + + '{value}' + + '
  • '; +function getConditions(chart) { + var _a; + var threshold = util_1.parseJson(chart.senior).threshold; + var annotations = []; + if (!threshold.enable || chart.type === 'area-stack' || chart.type === 'symbolic-map') + return annotations; + var conditions = (_a = threshold.lineThreshold) !== null && _a !== void 0 ? _a : []; + var yAxisIds = chart.yAxis.map(function (i) { return i.id; }); + for (var _i = 0, conditions_1 = conditions; _i < conditions_1.length; _i++) { + var field = conditions_1[_i]; + if (!yAxisIds.includes(field.fieldId)) { + continue; + } + for (var _b = 0, _c = field.conditions; _b < _c.length; _b++) { + var t = _c[_b]; + var annotation = { + type: 'regionFilter', + start: ['start', 'median'], + end: ['end', 'min'], + color: t.color + }; + // 加中线 + var annotationLine = { + type: 'line', + start: ['start', t.value], + end: ['end', t.value], + style: { + stroke: t.color, + lineDash: [2, 2] + } + }; + if (t.term === 'between') { + annotation.start = ['start', parseFloat(t.min)]; + annotation.end = ['end', parseFloat(t.max)]; + annotationLine.start = ['start', parseFloat(t.min)]; + annotationLine.end = ['end', parseFloat(t.min)]; + annotations.push(JSON.parse(JSON.stringify(annotationLine))); + annotationLine.start = ['start', parseFloat(t.max)]; + annotationLine.end = ['end', parseFloat(t.max)]; + annotations.push(annotationLine); + } + else if (['lt', 'le'].includes(t.term)) { + annotation.start = ['start', t.value]; + annotation.end = ['end', 'min']; + annotations.push(annotationLine); + } + else if (['gt', 'ge'].includes(t.term)) { + annotation.start = ['start', t.value]; + annotation.end = ['end', 'max']; + annotations.push(annotationLine); + } + annotations.push(annotation); + } + } + return annotations; +} +exports.getConditions = getConditions; +var AXIS_LABEL_TOOLTIP_STYLE = { + transition: 'left 0.4s cubic-bezier(0.23, 1, 0.32, 1) 0s, top 0.4s cubic-bezier(0.23, 1, 0.32, 1) 0s', + backgroundColor: 'rgb(255, 255, 255)', + boxShadow: 'rgb(174, 174, 174) 0px 0px 10px', + borderRadius: '3px', + padding: '8px 12px', + opacity: '0.95', + position: 'absolute', + visibility: 'visible' +}; +var AXIS_LABEL_TOOLTIP_TPL = '
    ' + '
    {title}
    ' + '
    '; +function configAxisLabelLengthLimit(chart, plot, triggerObjName) { + // 设置触发事件的名称,如果未传入,则默认为 'axis-label' + var triggerName = triggerObjName || 'axis-label'; + // 判断是否是Y轴标题 + var isYaxisTitle = triggerName === 'axis-title'; + // 解析图表的自定义样式和属性 + var _a = util_1.parseJson(chart), customStyle = _a.customStyle, customAttr = _a.customAttr; + var _b = customStyle.yAxis.axisLabel, lengthLimit = _b.lengthLimit, fontSize = _b.fontSize, color = _b.color, show = _b.show; + var tooltip = customAttr.tooltip; + // 如果不是标题,判断没有设置长度限制、没有显示或Y轴不显示,或图表类型为双向条形图,则不执行后续操作 + if (!isYaxisTitle && + (!lengthLimit || !show || !customStyle.yAxis.show || chart.type === 'bidirectional-bar')) + return; + // 鼠标进入事件 + plot.on(triggerName + ':mouseenter', function (e) { + var _a; + var field = e.target.cfg.delegateObject.component.cfg.field; + var position = e.target.cfg.delegateObject.component.cfg.position; + var isYaxis = position === 'left' || position === 'right'; + // 如果不是 'field' 或 'title',且不是Y轴,直接返回 + if (field !== 'field' && field !== 'title' && !isYaxis) + return; + // 获取轴标签的实际内容 + var realContent = e.target.attrs.text; + // 不是标题时,判断标签长度小于限制或已经省略(以'...'结尾),则不显示 tooltip + if (isYaxisTitle ? false : realContent.length < lengthLimit || !(realContent.slice(-3) === '...')) + return; + // 获取当前鼠标事件的坐标 + var x = e.x, y = e.y; + var parentNode = e.event.target.parentNode; + // 获取父节点中是否已有 tooltip + var labelTooltipDom = parentNode.getElementsByClassName('g2-axis-label-tooltip')[0]; + // 获取轴的标题 + var title = ((_a = e.target.cfg.delegateObject.item) === null || _a === void 0 ? void 0 : _a.name) || + e.target.cfg.delegateObject.axis.cfg.title.originalText; + // 如果没有 tooltip,创建新的 tooltip DOM 元素 + if (!labelTooltipDom) { + var domStr = substitute_1["default"](AXIS_LABEL_TOOLTIP_TPL, { title: title }); + labelTooltipDom = create_dom_1["default"](domStr); + // 设置 tooltip 的样式 + AXIS_LABEL_TOOLTIP_STYLE.backgroundColor = tooltip.backgroundColor; + AXIS_LABEL_TOOLTIP_STYLE.boxShadow = tooltip.backgroundColor + " 0px 0px 5px"; + AXIS_LABEL_TOOLTIP_STYLE.maxWidth = '200px'; + lodash_1["default"].assign(labelTooltipDom.style, AXIS_LABEL_TOOLTIP_STYLE); + // 将 tooltip 添加到父节点 + parentNode.appendChild(labelTooltipDom); + } + else { + // 如果已有 tooltip,更新其标题并使其可见 + labelTooltipDom.getElementsByClassName('g2-tooltip-title')[0].innerHTML = title; + labelTooltipDom.style.visibility = 'visible'; + } + // 获取父节点的尺寸和 tooltip 的尺寸 + var _b = parentNode.getBoundingClientRect(), height = _b.height, width = _b.width; + var offsetHeight = labelTooltipDom.offsetHeight, offsetWidth = labelTooltipDom.offsetWidth; + // 如果 tooltip 的尺寸超出了父节点的尺寸,则将其位置重置为 (0, 0) + if (offsetHeight > height || offsetWidth > width) { + labelTooltipDom.style.left = labelTooltipDom.style.top = '0px'; + return; + } + // 计算 tooltip 的初始位置 + var initPosition = { left: x + 10, top: y + 15 }; + // 调整位置,避免 tooltip 超出边界 + if (initPosition.left + offsetWidth > width) + initPosition.left = width - offsetWidth - 10; + if (initPosition.top + offsetHeight > height) + initPosition.top -= offsetHeight + 15; + // 设置 tooltip 的位置和样式 + labelTooltipDom.style.left = initPosition.left + "px"; + labelTooltipDom.style.top = initPosition.top + "px"; + labelTooltipDom.style.color = color; + labelTooltipDom.style.fontSize = fontSize + "px"; + }); + // 鼠标离开事件 + plot.on(triggerName + ':mouseleave', function (e) { + var field = e.target.cfg.delegateObject.component.cfg.field; + var position = e.target.cfg.delegateObject.component.cfg.position; + var isYaxis = position === 'left' || position === 'right'; + // 如果不是 'field' 或 'title',且不是Y轴,直接返回 + if (field !== 'field' && field !== 'title' && !isYaxis) + return; + // 获取轴标签的实际内容 + var realContent = e.target.attrs.text; + // 如果标签长度小于限制或已经省略(以'...'结尾),则不显示 tooltip + if (isYaxisTitle ? false : realContent.length < lengthLimit || !(realContent.slice(-3) === '...')) + return; + // 获取父节点中的 tooltip + var parentNode = e.event.target.parentNode; + var labelTooltipDom = parentNode.getElementsByClassName('g2-axis-label-tooltip')[0]; + // 如果 tooltip 存在,隐藏它 + if (labelTooltipDom) + labelTooltipDom.style.visibility = 'hidden'; + }); +} +exports.configAxisLabelLengthLimit = configAxisLabelLengthLimit; +/** + * y轴标题截取 + * @param chart + * @param plot + */ +function configYaxisTitleLengthLimit(chart, plot) { + // 监听图表渲染前事件 + plot.on('beforerender', function (ev) { + // 获取图表的Y轴自定义样式 + var yAxis = util_1.parseJson(chart.customStyle).yAxis; + // 计算最大可用空间高度,80% 为最大高度比 + var maxHeightRatio = 0.8 * (ev.view.canvas.cfg.height - (ev.view.canvas.cfg.height < 120 ? 60 : 30)); + // 计算Y轴标题的每行高度 + var titleHeight = util_1.measureText(chart, yAxis.name, { fontSize: yAxis.fontSize, fontFamily: chart.fontFamily }, 'height'); + // 用于存储截取后的标题 + var wrappedTitle = ''; + // 循环截取标题内容,直到超过最大高度 + for (var charIndex = 0; charIndex < yAxis.name.length && (charIndex + 1) * titleHeight <= maxHeightRatio; charIndex++) { + wrappedTitle += yAxis.name[charIndex]; + } + // 如果标题被截断,添加省略号 + if (yAxis.name.length > wrappedTitle.length) { + wrappedTitle = + wrappedTitle.length > 2 + ? wrappedTitle.slice(0, wrappedTitle.length - 2) + '...' + : wrappedTitle + '...'; + } + // 更新Y轴标题的原始文本和截断后的文本 + var title = ev.view.options.axes.yAxisExt.title; + if (title) { + title.originalText = yAxis.name; + title.text = wrappedTitle; + } + }); +} +exports.configYaxisTitleLengthLimit = configYaxisTitleLengthLimit; +/** + * 调整原始数据options.data + * 添加conditionColor字段,用于保存符合条件的颜色 + * conditionColor 为数组,多个指标多个颜色,按照指标的顺序 + * @param chart + * @param options + */ +exports.addConditionsStyleColorToData = function (chart, options) { + var threshold = util_1.parseJson(chart.senior).threshold; + if (!threshold.enable) + return options; + options.data.forEach(function (item) { + var _a, _b; + item['conditionColor'] = []; + // 条形图的值字段是xField,柱形图的值字段是yField + var valueField = chart.type === 'bar-horizontal' ? options.xField : options.yField; + // 对称条形图区分左右值,value、 valueExt,quotaList只有一个 + if (chart.type === 'bidirectional-bar') { + valueField.forEach(function (value) { + var _a; + var quotaList = value === 'value' ? chart.yAxis : chart.yAxisExt; + var conditionColor = getColorByConditions([(_a = quotaList[0]) === null || _a === void 0 ? void 0 : _a.id], item[value], chart); + if (conditionColor) { + item[item[options.xField] + '-' + value] = conditionColor; + } + }); + } + else if ((_a = item.quotaList) === null || _a === void 0 ? void 0 : _a.length) { + var quotaList = (_b = item.quotaList.map(function (q) { return q.id; })) !== null && _b !== void 0 ? _b : []; + quotaList.forEach(function (q) { + // 定义后,在 handleConditionsStyle 函数中使用 + var currentValue = item[valueField]; + if (chart.type === 'progress-bar') { + currentValue = item['originalValue']; + } + var cColor = getColorByConditions([q], currentValue, chart); + if (cColor) { + item.conditionColor.push(cColor); + } + else { + item.conditionColor = undefined; + } + }); + } + }); + return options; +}; +/** + * 辅助函数:获取颜色, 根据条件以及值计算 + * @param quotaList 指标列表 + * @param values 值 + */ +var getColorByConditions = function (quotaList, values, chart) { + var _a, _b, _c; + var threshold = util_1.parseJson(chart.senior).threshold; + var basicStyle = util_1.parseJson(chart.customAttr).basicStyle; + var currentValue = Array.isArray(values) ? values[1] - values[0] : values; + if (!currentValue) + return undefined; + // 同样的指标只取最后一个 + var conditionMap = new Map(); + for (var _i = 0, _d = (_a = threshold.lineThreshold) !== null && _a !== void 0 ? _a : []; _i < _d.length; _i++) { + var condition = _d[_i]; + conditionMap.set(condition.fieldId, condition); + } + var _loop_1 = function (condition) { + if (chart.type === 'progress-bar' && ((_c = (_b = chart.yAxisExt) === null || _b === void 0 ? void 0 : _b[0]) === null || _c === void 0 ? void 0 : _c.id) !== quotaList[0]) + return "continue"; + if (!quotaList.includes(condition.fieldId) && chart.type !== 'waterfall') + return "continue"; + for (var _i = 0, _a = condition.conditions; _i < _a.length; _i++) { + var tc = _a[_i]; + if ((tc.term === 'between' && currentValue >= tc.min && currentValue <= tc.max) || + (tc.term === 'lt' && currentValue < tc.value) || + (tc.term === 'le' && currentValue <= tc.value) || + (tc.term === 'gt' && currentValue > tc.value) || + (tc.term === 'ge' && currentValue >= tc.value)) { + var tmpColor = util_1.hexToRgba(tc.color, basicStyle.alpha); + if (basicStyle.gradient) { + var vhAngle = ['bar-horizontal', 'progress-bar'].includes(chart.type) ? 0 : 270; + if (chart.type === 'bidirectional-bar') { + var yAxis = chart.yAxis.find(function (item) { return item.id === condition.fieldId; }); + vhAngle = getBidirectionalAngle(basicStyle, yAxis ? 0 : 1); + } + tmpColor = setGradientColor(tmpColor, true, vhAngle); + } + return { value: tmpColor }; + } + } + }; + for (var _e = 0, _f = conditionMap.values(); _e < _f.length; _e++) { + var condition = _f[_e]; + var state_1 = _loop_1(condition); + if (typeof state_1 === "object") + return state_1.value; + } +}; +/** + * 处理柱条图的样式 + * 柱条的颜色 + * 提示marker的颜色 + * 注: 原始options中tooltip已经配置了customItems,这里将会忽略 + * @param chart + * @param options + */ +function handleConditionsStyle(chart, options) { + var threshold = util_1.parseJson(chart.senior).threshold; + if (!threshold.enable) + return options; + var basicStyle = util_1.parseJson(chart.customAttr).basicStyle; + // 该字段出处 addConditionsStyleColorToData + var colorField = 'conditionColor'; + // 配置条件样式的颜色字段 + var rawFields = options.rawFields || []; + rawFields.push(colorField); + // 辅助函数:配置柱条样式颜色,条形图为barStyle,柱形图为columnStyle + var columnStyle = function (data) { + var _a; + return __assign({}, (((_a = data[colorField]) === null || _a === void 0 ? void 0 : _a[0]) ? { fill: data[colorField][0] } : {})); + }; + var newColor = undefined; + if (chart.type === 'bidirectional-bar') { + rawFields.push(options.xField); + newColor = getBidirectionalBarColor(chart, basicStyle, options); + } + else if (chart.type === 'waterfall') { + newColor = getWaterfallColor(basicStyle, chart); + } + var tmpOption = __assign(__assign(__assign(__assign(__assign(__assign({}, options), { rawFields: rawFields }), exports.configRoundAngle(chart, 'columnStyle', columnStyle)), exports.configRoundAngle(chart, 'barStyle', columnStyle)), { tooltip: __assign(__assign({}, options.tooltip), (options.tooltip['customItems'] + ? {} + : { + customItems: function (originalItems) { + originalItems.forEach(function (item) { + var _a; + if ((_a = item.data) === null || _a === void 0 ? void 0 : _a[colorField]) { + item.color = item.data[colorField][0]; + } + }); + return originalItems; + } + })) }), (newColor ? { color: newColor } : {})); + return tmpOption; +} +exports.handleConditionsStyle = handleConditionsStyle; +/** + * 配置瀑布图的color + * 瀑布color,这个图表固定为基础样式中颜色的前三个颜色,第一个为增加,第二个为减少,第三个为总计 + * @param basicStyle + * @param chart + */ +var getWaterfallColor = function (basicStyle, chart) { + var waterfallBasicColors = getBasicColors(chart, basicStyle, 270); + return function (data) { + if (data['$$isTotal$$']) + return waterfallBasicColors[2]; + var values = data['$$yField$$']; + var newColor = getColorByConditions([], values, chart); + return newColor !== null && newColor !== void 0 ? newColor : (values[1] > values[0] ? waterfallBasicColors[0] : waterfallBasicColors[1]); + }; +}; +/** + * 配置对称条形图的color + * @param basicStyle + * @param options + */ +var getBidirectionalBarColor = function (chart, basicStyle, options) { + var basicColors = getBasicColors(chart, basicStyle, 270); + return function (ref) { + var obj = options.data.find(function (item) { return item[ref[options.xField] + '-' + ref['series-field-key']]; }); + if (obj) { + return obj[ref[options.xField] + '-' + ref['series-field-key']]; + } + return ref['series-field-key'] === 'value' ? basicColors[0] : basicColors[1]; + }; +}; +/** + * 获取基础颜色 + * @param chart + * @param basicStyle + * @param angle + */ +var getBasicColors = function (chart, basicStyle, angle) { + var _a; + var baseColors = []; + (_a = basicStyle.colors) === null || _a === void 0 ? void 0 : _a.forEach(function (color, index) { + if (chart.type === 'bidirectional-bar') { + baseColors.push(setGradientColor(util_1.hexToRgba(color, basicStyle.alpha), true, getBidirectionalAngle(basicStyle, index))); + } + else { + baseColors.push(setGradientColor(util_1.hexToRgba(color, basicStyle.alpha), true, angle)); + } + }); + return basicStyle.gradient ? baseColors : basicStyle.colors; +}; +/** + * 获取对称条形图颜色的渐变角度 + * @param basicStyle + * @param index + */ +var getBidirectionalAngle = function (basicStyle, index) { + var vhAngle = 180 - index * 180; + if (basicStyle.layout === 'vertical') { + vhAngle = index === 0 ? 280 : 90; + } + return vhAngle; +}; +/** + * tooltip验证条件样式中的颜色,有就使用,否则使用原始颜色 + * @param item + */ +exports.getTooltipItemConditionColor = function (item) { + var _a; + var color = item.color; + if ((_a = item.data) === null || _a === void 0 ? void 0 : _a['conditionColor']) { + color = item.data['conditionColor'][0]; + } + return color; +}; +/** + * 配置空数据样式 + * @param newChart + * @param newData + * @param container + */ +exports.configEmptyDataStyle = function (newData, container, newChart, content) { + /** + * 辅助函数:移除空数据dom + */ + var removeEmptyDom = function () { + var emptyElement = document.getElementById(container + '_empty'); + if (emptyElement) { + emptyElement.parentElement.removeChild(emptyElement); + } + }; + removeEmptyDom(); + if (newData.length > 0) + return; + if (!newData.length) { + var emptyDom = document.createElement('div'); + emptyDom.id = container + '_empty'; + emptyDom.textContent = content || tI18n('data_set.no_data'); + emptyDom.setAttribute('style', "position: absolute;\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n color: darkgray;\n textAlign: center;"); + var parent = document.getElementById(container); + parent.insertBefore(emptyDom, parent.firstChild); + newChart === null || newChart === void 0 ? void 0 : newChart.destroy(); + } +}; +exports.numberToChineseUnderHundred = function (num) { + // 合法性检查 + if (num <= 0 || num > 99 || !Number.isInteger(num)) { + throw new Error('请输入1-99之间的整数'); + } + var digits = ['', '一', '二', '三', '四', '五', '六', '七', '八', '九']; + // 处理个位数 + if (num < 10) + return digits[num]; + var tens = Math.floor(num / 10); + var ones = num % 10; + // 处理整十 + if (ones === 0) { + return tens === 1 ? '十' : digits[tens] + '十'; + } + // 处理其他两位数 + return tens === 1 ? '十' + digits[ones] : digits[tens] + '十' + digits[ones]; +}; +/** + * 配置柱条图的圆角 + * @param styleName + * @param callBack 自定义其他属性函数 + */ +exports.configRoundAngle = function (chart, styleName, callBack) { + var _a, _b, _c, _d, _e, _f; + var basicStyle = util_1.parseJson(chart.customAttr).basicStyle; + if (['roundAngle', 'topRoundAngle'].includes(basicStyle.radiusColumnBar)) { + var radius_1 = Array(2).fill(basicStyle.columnBarRightAngleRadius); + var topRadius_1 = __spreadArrays([0, 0], radius_1); + var bottomRadius_1 = __spreadArrays(radius_1, [0, 0]); + var finalRadius_1 = __spreadArrays(radius_1, radius_1); + if (chart.type.includes('-stack')) { + return _a = {}, + _a[styleName] = function (datum) { + if (!datum.value) + return __assign({ radius: [] }, (callBack ? callBack(datum) : {})); + return __assign({ radius: finalRadius_1 }, (callBack ? callBack(datum) : {})); + }, + _a; + } + var isTopRound_1 = basicStyle.radiusColumnBar === 'topRoundAngle'; + // 对称条形图 + if (chart.type === 'bidirectional-bar') { + var valueField_1 = basicStyle.layout === 'vertical' ? 'valueExt' : 'value'; + return _b = {}, + _b[styleName] = function (datum) { return (__assign({ radius: datum[valueField_1] && isTopRound_1 ? topRadius_1 : isTopRound_1 ? radius_1 : finalRadius_1 }, (callBack ? callBack(datum) : {}))); }, + _b; + } + // 进度条 + if (chart.type === 'progress-bar') { + return _c = {}, + _c[styleName] = function (datum) { + return __assign({ radius: isTopRound_1 ? bottomRadius_1 : finalRadius_1 }, (callBack ? callBack(datum) : {})); + }, + _c; + } + // 区间条形图 + if (chart.type === 'bar-range') { + return _d = {}, + _d[styleName] = function (datum) { + return __assign({ radius: (datum === null || datum === void 0 ? void 0 : datum.values[0]) < (datum === null || datum === void 0 ? void 0 : datum.values[1]) + ? isTopRound_1 + ? bottomRadius_1 + : finalRadius_1 + : isTopRound_1 + ? topRadius_1 + : finalRadius_1 }, (callBack ? callBack(datum) : {})); + }, + _d; + } + // 配置柱条样式 + var style = function (datum) { + if (isTopRound_1) { + return __assign({ radius: radius_1 }, (callBack ? callBack(datum) : {})); + } + if (!isTopRound_1) { + return __assign({ radius: finalRadius_1 }, (callBack ? callBack(datum) : {})); + } + }; + return _e = {}, + _e[styleName] = style, + _e; + } + return _f = {}, + _f[styleName] = function (datum) { + return __assign({}, (callBack ? callBack(datum) : {})); + }, + _f; +}; diff --git a/frontend/src/data-visualization/chart/components/js/panel/common/dist/common_table.js b/frontend/src/data-visualization/chart/components/js/panel/common/dist/common_table.js new file mode 100644 index 0000000..00eda3e --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/common/dist/common_table.js @@ -0,0 +1,2442 @@ +"use strict"; +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var __assign = (this && this.__assign) || function () { + __assign = Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; + }; + return __assign.apply(this, arguments); +}; +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __generator = (this && this.__generator) || function (thisArg, body) { + var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; + return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; + function verb(n) { return function (v) { return step([n, v]); }; } + function step(op) { + if (f) throw new TypeError("Generator is already executing."); + while (_) try { + if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; + if (y = 0, t) op = [op[0] & 2, t.value]; + switch (op[0]) { + case 0: case 1: t = op; break; + case 4: _.label++; return { value: op[1], done: false }; + case 5: _.label++; y = op[1]; op = [0]; continue; + case 7: op = _.ops.pop(); _.trys.pop(); continue; + default: + if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } + if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } + if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } + if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } + if (t[2]) _.ops.pop(); + _.trys.pop(); continue; + } + op = body.call(thisArg, _); + } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } + if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; + } +}; +var __spreadArrays = (this && this.__spreadArrays) || function () { + for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; + for (var r = Array(s), k = 0, i = 0; i < il; i++) + for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) + r[k] = a[j]; + return r; +}; +var _this = this; +exports.__esModule = true; +exports.drawImage = exports.getColumns = exports.getLeafNodes = exports.configEmptyDataStyle = exports.SummaryCell = exports.getSummaryRow = exports.calculateHeaderHeight = exports.CustomTableColCell = exports.CustomDataCell = exports.getRowIndex = exports.configMergeCells = exports.exportPivotExcel = exports.exportRowQuotaTreePivot = exports.exportTreePivot = exports.exportRowQuotaGridPivot = exports.exportGridPivot = exports.copyContent = exports.configTooltip = exports.configHeaderInteraction = exports.SortTooltip = exports.handleTableEmptyStrategy = exports.mappingColor = exports.getConditions = exports.getCurrentField = exports.getStyle = exports.getCustomTheme = void 0; +/* eslint-disable prettier/prettier */ +var util_1 = require("../..//util"); +var chart_1 = require("@/views/chart/components/editor/util/chart"); +var s2_1 = require("@antv/s2"); +var lodash_es_1 = require("lodash-es"); +var vue_1 = require("vue"); +var TableTooltip_vue_1 = require("@/views/chart/components/editor/common/TableTooltip.vue"); +var exceljs_1 = require("exceljs"); +var file_saver_1 = require("file-saver"); +var element_plus_secondary_1 = require("element-plus-secondary"); +var useI18n_1 = require("@/hooks/web/useI18n"); +var decimal_js_1 = require("decimal.js"); +var i18nt = useI18n_1.useI18n().t; +function getCustomTheme(chart) { + var headerColor = util_1.hexColorToRGBA(chart_1.DEFAULT_TABLE_HEADER.tableHeaderBgColor, chart_1.DEFAULT_BASIC_STYLE.alpha); + var headerAlign = chart_1.DEFAULT_TABLE_HEADER.tableHeaderAlign; + var itemColor = util_1.hexColorToRGBA(chart_1.DEFAULT_TABLE_CELL.tableItemBgColor, chart_1.DEFAULT_BASIC_STYLE.alpha); + var itemAlign = chart_1.DEFAULT_TABLE_CELL.tableItemAlign; + var borderColor = util_1.hexColorToRGBA(chart_1.DEFAULT_BASIC_STYLE.tableBorderColor, chart_1.DEFAULT_BASIC_STYLE.alpha); + var scrollBarColor = chart_1.DEFAULT_BASIC_STYLE.tableScrollBarColor; + var scrollBarHoverColor = util_1.resetRgbOpacity(scrollBarColor, 3); + var textFontFamily = chart.fontFamily && chart.fontFamily !== 'inherit' ? chart.fontFamily : s2_1.FONT_FAMILY; + var theme = { + background: { + color: '#00000000' + }, + splitLine: { + horizontalBorderColor: borderColor, + horizontalBorderColorOpacity: 1, + horizontalBorderWidth: 1, + verticalBorderColor: borderColor, + verticalBorderColorOpacity: 1, + verticalBorderWidth: 1, + showShadow: false + }, + cornerCell: { + cell: { + backgroundColor: headerColor, + horizontalBorderColor: borderColor, + verticalBorderColor: borderColor + }, + text: { + fill: chart_1.DEFAULT_TABLE_HEADER.tableHeaderFontColor, + fontSize: chart_1.DEFAULT_TABLE_HEADER.tableTitleFontSize, + textAlign: headerAlign, + fontFamily: textFontFamily + }, + bolderText: { + fill: chart_1.DEFAULT_TABLE_HEADER.tableHeaderFontColor, + fontSize: chart_1.DEFAULT_TABLE_HEADER.tableTitleFontSize, + textAlign: headerAlign, + fontFamily: textFontFamily + }, + measureText: { + fill: chart_1.DEFAULT_TABLE_HEADER.tableHeaderFontColor, + fontSize: chart_1.DEFAULT_TABLE_HEADER.tableTitleFontSize, + textAlign: headerAlign, + fontFamily: textFontFamily + } + }, + rowCell: { + cell: { + backgroundColor: headerColor, + horizontalBorderColor: borderColor, + verticalBorderColor: borderColor + }, + text: { + fill: chart_1.DEFAULT_TABLE_HEADER.tableHeaderFontColor, + fontSize: chart_1.DEFAULT_TABLE_HEADER.tableTitleFontSize, + textAlign: headerAlign, + textBaseline: 'middle', + fontFamily: textFontFamily + }, + bolderText: { + fill: chart_1.DEFAULT_TABLE_HEADER.tableHeaderFontColor, + fontSize: chart_1.DEFAULT_TABLE_HEADER.tableTitleFontSize, + textAlign: headerAlign, + fontFamily: textFontFamily + }, + measureText: { + fill: chart_1.DEFAULT_TABLE_HEADER.tableHeaderFontColor, + fontSize: chart_1.DEFAULT_TABLE_HEADER.tableTitleFontSize, + textAlign: headerAlign, + fontFamily: textFontFamily + }, + seriesText: { + fill: chart_1.DEFAULT_TABLE_CELL.tableItemBgColor, + fontSize: chart_1.DEFAULT_TABLE_CELL.tableItemFontSize, + textAlign: itemAlign, + fontFamily: textFontFamily + } + }, + colCell: { + cell: { + backgroundColor: headerColor, + horizontalBorderColor: borderColor, + verticalBorderColor: borderColor + }, + text: { + fill: chart_1.DEFAULT_TABLE_HEADER.tableHeaderFontColor, + fontSize: chart_1.DEFAULT_TABLE_HEADER.tableTitleFontSize, + textAlign: headerAlign, + fontFamily: textFontFamily + }, + bolderText: { + fill: chart_1.DEFAULT_TABLE_HEADER.tableHeaderFontColor, + fontSize: chart_1.DEFAULT_TABLE_HEADER.tableTitleFontSize, + textAlign: headerAlign, + fontFamily: textFontFamily + }, + measureText: { + fill: chart_1.DEFAULT_TABLE_HEADER.tableHeaderFontColor, + fontSize: chart_1.DEFAULT_TABLE_HEADER.tableTitleFontSize, + textAlign: headerAlign, + fontFamily: textFontFamily + } + }, + dataCell: { + cell: { + backgroundColor: itemColor, + horizontalBorderColor: borderColor, + verticalBorderColor: borderColor + }, + text: { + fill: chart_1.DEFAULT_TABLE_CELL.tableFontColor, + fontSize: chart_1.DEFAULT_TABLE_CELL.tableItemFontSize, + textAlign: itemAlign, + fontFamily: textFontFamily + }, + bolderText: { + fill: chart_1.DEFAULT_TABLE_CELL.tableFontColor, + fontSize: chart_1.DEFAULT_TABLE_CELL.tableItemFontSize, + textAlign: itemAlign, + fontFamily: textFontFamily + }, + measureText: { + fill: chart_1.DEFAULT_TABLE_CELL.tableFontColor, + fontSize: chart_1.DEFAULT_TABLE_CELL.tableItemFontSize, + textAlign: headerAlign, + fontFamily: textFontFamily + } + }, + scrollBar: { + thumbColor: scrollBarColor, + thumbHoverColor: scrollBarHoverColor, + size: 8, + hoverSize: 12 + } + }; + var customAttr; + if (chart.customAttr) { + customAttr = util_1.parseJson(chart.customAttr); + var basicStyle = customAttr.basicStyle, tableHeader = customAttr.tableHeader, tableCell = customAttr.tableCell; + // basic + if (basicStyle) { + var tableBorderColor = basicStyle.tableBorderColor; + var tableScrollBarColor = basicStyle.tableScrollBarColor; + var tmpTheme = { + splitLine: { + horizontalBorderColor: tableBorderColor, + verticalBorderColor: tableBorderColor + }, + cornerCell: { + cell: { + horizontalBorderColor: tableBorderColor, + verticalBorderColor: tableBorderColor + } + }, + colCell: { + cell: { + horizontalBorderColor: tableBorderColor, + verticalBorderColor: tableBorderColor + } + }, + dataCell: { + cell: { + horizontalBorderColor: tableBorderColor, + verticalBorderColor: tableBorderColor, + interactionState: { + hoverFocus: { + borderOpacity: basicStyle.showHoverStyle === false ? 0 : 1 + } + } + } + }, + scrollBar: { + thumbColor: tableScrollBarColor, + thumbHoverColor: util_1.resetRgbOpacity(tableScrollBarColor, 1.5) + } + }; + lodash_es_1.merge(theme, tmpTheme); + } + // header + if (tableHeader) { + var tableHeaderFontColor = util_1.hexColorToRGBA(tableHeader.tableHeaderFontColor, basicStyle.alpha); + var tableHeaderBgColor = tableHeader.tableHeaderBgColor; + if (!util_1.isAlphaColor(tableHeaderBgColor)) { + tableHeaderBgColor = util_1.hexColorToRGBA(tableHeaderBgColor, basicStyle.alpha); + } + var fontStyle = tableHeader.isItalic ? 'italic' : 'normal'; + var fontWeight = tableHeader.isBolder === false ? 'normal' : 'bold'; + var tableHeaderAlign = tableHeader.tableHeaderAlign, tableTitleFontSize = tableHeader.tableTitleFontSize; + var tmpTheme = { + cornerCell: { + cell: { + backgroundColor: tableHeaderBgColor + }, + bolderText: { + fill: tableHeaderFontColor, + fontSize: tableTitleFontSize, + textAlign: tableHeaderAlign, + fontStyle: fontStyle, + fontWeight: fontWeight, + fontFamily: textFontFamily + }, + text: { + fill: tableHeaderFontColor, + fontSize: tableTitleFontSize, + textAlign: tableHeaderAlign, + fontStyle: fontStyle, + fontWeight: fontWeight, + fontFamily: textFontFamily + }, + measureText: { + fill: tableHeaderFontColor, + fontSize: tableTitleFontSize, + textAlign: tableHeaderAlign, + fontStyle: fontStyle, + fontWeight: fontWeight, + fontFamily: textFontFamily + } + }, + colCell: { + cell: { + backgroundColor: tableHeaderBgColor + }, + bolderText: { + fill: tableHeaderFontColor, + fontSize: tableTitleFontSize, + textAlign: tableHeaderAlign, + fontStyle: fontStyle, + fontWeight: fontWeight, + fontFamily: textFontFamily + }, + text: { + fill: tableHeaderFontColor, + fontSize: tableTitleFontSize, + textAlign: tableHeaderAlign, + fontStyle: fontStyle, + fontWeight: fontWeight, + fontFamily: textFontFamily + }, + measureText: { + fill: tableHeaderFontColor, + fontSize: tableTitleFontSize, + textAlign: tableHeaderAlign, + fontStyle: fontStyle, + fontWeight: fontWeight, + fontFamily: textFontFamily + } + } + }; + lodash_es_1.merge(theme, tmpTheme); + // 这边设置为 0 的话就会显示表头背景颜色,所以要判断一下表头是否关闭 + if (tableHeader.showHorizonBorder === false && tableHeader.showTableHeader !== false) { + var tmpTheme_1 = { + splitLine: { + horizontalBorderColor: tableHeaderBgColor, + horizontalBorderWidth: 0, + horizontalBorderColorOpacity: 0 + }, + colCell: { + cell: { + horizontalBorderColor: tableHeaderBgColor, + horizontalBorderWidth: 0 + } + } + }; + lodash_es_1.merge(theme, tmpTheme_1); + } + if (tableHeader.showVerticalBorder === false && tableHeader.showTableHeader !== false) { + var tmpTheme_2 = { + splitLine: { + verticalBorderColor: tableHeaderBgColor, + verticalBorderWidth: 0, + verticalBorderColorOpacity: 0 + }, + colCell: { + cell: { + verticalBorderColor: tableHeaderBgColor, + verticalBorderWidth: 0 + } + }, + cornerCell: { + cell: { + verticalBorderColor: tableHeaderBgColor, + verticalBorderWidth: 0 + } + } + }; + lodash_es_1.merge(theme, tmpTheme_2); + } + } + // cell + if (tableCell) { + var tableFontColor = util_1.hexColorToRGBA(tableCell.tableFontColor, basicStyle.alpha); + var tableItemBgColor = tableCell.tableItemBgColor; + if (!util_1.isAlphaColor(tableItemBgColor)) { + tableItemBgColor = util_1.hexColorToRGBA(tableItemBgColor, basicStyle.alpha); + } + var tableItemSubBgColor = tableCell.tableItemSubBgColor; + if (!util_1.isAlphaColor(tableItemSubBgColor)) { + tableItemSubBgColor = util_1.hexColorToRGBA(tableItemSubBgColor, basicStyle.alpha); + } + var fontStyle = tableCell.isItalic ? 'italic' : 'normal'; + var fontWeight = tableCell.isBolder === false ? 'normal' : 'bold'; + var tableItemAlign = tableCell.tableItemAlign, tableItemFontSize = tableCell.tableItemFontSize, enableTableCrossBG = tableCell.enableTableCrossBG; + var tmpTheme = { + rowCell: { + cell: { + backgroundColor: tableItemBgColor, + horizontalBorderColor: tableItemBgColor, + verticalBorderColor: tableItemBgColor + }, + bolderText: { + fill: tableFontColor, + textAlign: tableItemAlign, + fontSize: tableItemFontSize, + fontFamily: textFontFamily + }, + text: { + fill: tableFontColor, + textAlign: tableItemAlign, + fontSize: tableItemFontSize, + fontFamily: textFontFamily + }, + measureText: { + fill: tableFontColor, + textAlign: tableItemAlign, + fontSize: tableItemFontSize, + fontFamily: textFontFamily + }, + seriesText: { + fill: tableFontColor, + textAlign: tableItemAlign, + fontSize: tableItemFontSize, + fontFamily: textFontFamily + } + }, + dataCell: { + cell: { + crossBackgroundColor: enableTableCrossBG ? tableItemSubBgColor : tableItemBgColor, + backgroundColor: tableItemBgColor + }, + bolderText: { + fill: tableFontColor, + textAlign: tableItemAlign, + fontSize: tableItemFontSize, + fontStyle: fontStyle, + fontWeight: fontWeight, + fontFamily: textFontFamily + }, + text: { + fill: tableFontColor, + textAlign: tableItemAlign, + fontSize: tableItemFontSize, + fontStyle: fontStyle, + fontWeight: fontWeight, + fontFamily: textFontFamily + }, + measureText: { + fill: tableFontColor, + textAlign: tableItemAlign, + fontSize: tableItemFontSize, + fontStyle: fontStyle, + fontWeight: fontWeight, + fontFamily: textFontFamily + }, + seriesText: { + fill: tableFontColor, + textAlign: tableItemAlign, + fontSize: tableItemFontSize, + fontStyle: fontStyle, + fontWeight: fontWeight, + fontFamily: textFontFamily + } + } + }; + lodash_es_1.merge(theme, tmpTheme); + if (tableCell.showHorizonBorder === false) { + var tmpTheme_3 = { + dataCell: { + cell: { + horizontalBorderColor: tableItemBgColor, + horizontalBorderWidth: 0 + } + } + }; + lodash_es_1.merge(theme, tmpTheme_3); + } + if (tableCell.showVerticalBorder === false) { + var tmpTheme_4 = { + splitLine: { + verticalBorderWidth: 0, + verticalBorderColorOpacity: 0 + }, + dataCell: { + cell: { + verticalBorderColor: tableItemBgColor, + verticalBorderWidth: 0 + } + } + }; + lodash_es_1.merge(theme, tmpTheme_4); + } + } + } + return theme; +} +exports.getCustomTheme = getCustomTheme; +function getStyle(chart, dataConfig) { + var _a, _b, _c; + var style = {}; + var customAttr; + if (chart.customAttr) { + customAttr = util_1.parseJson(chart.customAttr); + var basicStyle_1 = customAttr.basicStyle, tableHeader_1 = customAttr.tableHeader, tableCell = customAttr.tableCell; + style.colCfg = { + height: tableHeader_1.tableTitleHeight + }; + style.cellCfg = { + height: tableCell.tableItemHeight + }; + switch (basicStyle_1.tableColumnMode) { + case 'adapt': { + style.layoutWidthType = 'compact'; + break; + } + case 'field': { + delete style.layoutWidthType; + var fieldMap_1 = ((_a = basicStyle_1.tableFieldWidth) === null || _a === void 0 ? void 0 : _a.reduce(function (p, n) { + p[n.fieldId] = n; + return p; + }, {})) || {}; + // 下钻字段使用入口字段的宽度 + if (chart.drill) { + var xAxis = util_1.parseJson(chart).xAxis; + var curDrillField = chart.drillFields[chart.drillFilters.length]; + var drillEnterFieldIndex = xAxis.findIndex(function (item) { return item.id === chart.drillFilters[0].fieldId; }); + var drillEnterField = xAxis[drillEnterFieldIndex]; + fieldMap_1[curDrillField.gisbiName] = { + width: (_b = fieldMap_1[drillEnterField.gisbiName]) === null || _b === void 0 ? void 0 : _b.width + }; + } + // 铺满 + var totalWidthPercent = (_c = dataConfig.meta) === null || _c === void 0 ? void 0 : _c.reduce(function (p, n) { + var _a, _b; + return p + ((_b = (_a = fieldMap_1[n.field]) === null || _a === void 0 ? void 0 : _a.width) !== null && _b !== void 0 ? _b : 10); + }, 0); + var fullFilled_1 = parseInt(totalWidthPercent.toFixed(0)) === 100; + var widthArr_1 = []; + style.colCfg.width = function (node) { + var _a; + var width = node.spreadsheet.container.cfg.el.getBoundingClientRect().width; + if (!((_a = basicStyle_1.tableFieldWidth) === null || _a === void 0 ? void 0 : _a.length)) { + var fieldsSize = chart.data.fields.length; + var columnCount = tableHeader_1.showIndex ? fieldsSize + 1 : fieldsSize; + return width / columnCount; + } + var baseWidth = width / 100; + var tmpWidth = fieldMap_1[node.field] + ? fieldMap_1[node.field].width * baseWidth + : baseWidth * 10; + var resultWidth = parseInt(tmpWidth.toFixed(0)); + if (fullFilled_1) { + if (widthArr_1.length === dataConfig.meta.length - 1) { + var curTotalWidth = widthArr_1.reduce(function (p, n) { + return p + n; + }, 0); + var restWidth = width - curTotalWidth; + widthArr_1.splice(0); + if (restWidth < resultWidth) { + return restWidth; + } + } + else { + widthArr_1.push(resultWidth); + } + } + return resultWidth; + }; + break; + } + case 'custom': { + style.colCfg.width = basicStyle_1.tableColumnWidth; + break; + } + // 查看详情用,均分铺满 + default: { + delete style.layoutWidthType; + style.colCfg.width = function (node) { + var width = node.spreadsheet.container.cfg.el.offsetWidth; + var fieldsSize = node.spreadsheet.dataCfg.meta.length; + if (!fieldsSize) { + return 0; + } + var columnCount = tableHeader_1.showIndex ? fieldsSize + 1 : fieldsSize; + var minWidth = width / columnCount; + return Math.max(minWidth, basicStyle_1.tableColumnWidth); + }; + } + } + } + return style; +} +exports.getStyle = getStyle; +function getCurrentField(valueFieldList, field) { + var list = []; + var res = null; + try { + list = util_1.parseJson(valueFieldList); + } + catch (err) { + list = JSON.parse(JSON.stringify(valueFieldList)); + } + if (list) { + for (var i = 0; i < list.length; i++) { + var f = list[i]; + if (field.gisbiName === f.gisbiName) { + res = f; + break; + } + } + } + return res; +} +exports.getCurrentField = getCurrentField; +function getConditions(chart) { + var _a; + var threshold = util_1.parseJson(chart.senior).threshold; + if (!threshold.enable) { + return; + } + var res = { + text: [], + background: [] + }; + var conditions = (_a = threshold.tableThreshold) !== null && _a !== void 0 ? _a : []; + var dimFields = __spreadArrays(chart.xAxis, chart.xAxisExt).map(function (i) { return i.gisbiName; }); + if ((conditions === null || conditions === void 0 ? void 0 : conditions.length) > 0) { + var _b = util_1.parseJson(chart.customAttr), tableCell = _b.tableCell, basicStyle = _b.basicStyle, tableHeader = _b.tableHeader; + // 合并单元格时斑马纹失效 + var enableTableCrossBG = chart.type === 'table-info' + ? tableCell.enableTableCrossBG && !tableCell.mergeCells + : tableCell.enableTableCrossBG; + var valueColor = util_1.isAlphaColor(tableCell.tableFontColor) + ? tableCell.tableFontColor + : util_1.hexColorToRGBA(tableCell.tableFontColor, basicStyle.alpha); + var valueBgColor = enableTableCrossBG + ? null + : util_1.isAlphaColor(tableCell.tableItemBgColor) + ? tableCell.tableItemBgColor + : util_1.hexColorToRGBA(tableCell.tableItemBgColor, basicStyle.alpha); + var headerValueColor = tableHeader.tableHeaderFontColor; + var headerValueBgColor = util_1.isAlphaColor(tableHeader.tableHeaderBgColor) + ? tableHeader.tableHeaderBgColor + : util_1.hexColorToRGBA(tableHeader.tableHeaderBgColor, basicStyle.alpha); + var filedValueMap_1 = getFieldValueMap(chart); + var _loop_1 = function (i) { + var field = conditions[i]; + var defaultValueColor = valueColor; + var defaultBgColor = valueBgColor; + // 透视表表头颜色配置 + if (chart.type === 'table-pivot' && dimFields.includes(field.field.gisbiName)) { + defaultValueColor = headerValueColor; + defaultBgColor = headerValueBgColor; + } + res.text.push({ + field: field.field.gisbiName, + mapping: function (value, rowData) { + // 总计小计 + if (rowData === null || rowData === void 0 ? void 0 : rowData.isTotals) { + return null; + } + // 表头 + if ((rowData === null || rowData === void 0 ? void 0 : rowData.id) && (rowData === null || rowData === void 0 ? void 0 : rowData.field) === rowData.id) { + return null; + } + return { + fill: mappingColor(value, defaultValueColor, field, 'color', filedValueMap_1, rowData) + }; + } + }); + res.background.push({ + field: field.field.gisbiName, + mapping: function (value, rowData) { + if (rowData === null || rowData === void 0 ? void 0 : rowData.isTotals) { + return null; + } + if ((rowData === null || rowData === void 0 ? void 0 : rowData.id) && (rowData === null || rowData === void 0 ? void 0 : rowData.field) === rowData.id) { + return null; + } + var fill = mappingColor(value, defaultBgColor, field, 'backgroundColor', filedValueMap_1, rowData); + if (util_1.isTransparent(fill)) { + return null; + } + return { fill: fill }; + } + }); + }; + for (var i = 0; i < conditions.length; i++) { + _loop_1(i); + } + } + return res; +} +exports.getConditions = getConditions; +function mappingColor(value, defaultColor, field, type, filedValueMap, rowData) { + var color = null; + for (var i = 0; i < field.conditions.length; i++) { + var flag = false; + var t = field.conditions[i]; + var tv = void 0, max = void 0, min = void 0; + if (t.type === 'dynamic') { + if (t.term === 'between') { + max = parseFloat(getValue(t.dynamicMaxField, filedValueMap, rowData)); + min = parseFloat(getValue(t.dynamicMinField, filedValueMap, rowData)); + } + else { + tv = getValue(t.dynamicField, filedValueMap, rowData); + } + } + else { + if (t.term === 'between') { + min = parseFloat(t.min); + max = parseFloat(t.max); + } + else { + tv = t.value; + } + } + if (field.field.deType === 2 || field.field.deType === 3 || field.field.deType === 4) { + tv = parseFloat(tv); + if (t.term === 'eq') { + if (value === tv) { + color = t[type]; + flag = true; + } + } + else if (t.term === 'not_eq') { + if (value !== tv) { + color = t[type]; + flag = true; + } + } + else if (t.term === 'lt') { + if (value < tv) { + color = t[type]; + flag = true; + } + } + else if (t.term === 'gt') { + if (value > tv) { + color = t[type]; + flag = true; + } + } + else if (t.term === 'le') { + if (value <= tv) { + color = t[type]; + flag = true; + } + } + else if (t.term === 'ge') { + if (value >= tv) { + color = t[type]; + flag = true; + } + } + else if (t.term === 'between') { + if (min <= value && value <= max) { + color = t[type]; + flag = true; + } + } + else if (t.term === 'default') { + color = t[type]; + flag = true; + } + if (flag) { + break; + } + else if (i === field.conditions.length - 1) { + color = defaultColor; + } + } + else if (field.field.deType === 0 || field.field.deType === 5) { + if (t.term === 'eq') { + if (value === tv) { + color = t[type]; + flag = true; + } + } + else if (t.term === 'not_eq') { + if (value !== tv) { + color = t[type]; + flag = true; + } + } + else if (t.term === 'like') { + if (value.includes(tv)) { + color = t[type]; + flag = true; + } + } + else if (t.term === 'not like') { + if (!value.includes(tv)) { + color = t[type]; + flag = true; + } + } + else if (t.term === 'null') { + if (value === null || value === undefined || value === '') { + color = t[type]; + flag = true; + } + } + else if (t.term === 'not_null') { + if (value !== null && value !== undefined && value !== '') { + color = t[type]; + flag = true; + } + } + else if (t.term === 'default') { + color = t[type]; + flag = true; + } + if (flag) { + break; + } + else if (i === field.conditions.length - 1) { + color = defaultColor; + } + } + else { + // time + if (!tv || !value) { + break; + } + var fc = field.conditions[i]; + tv = new Date(tv.replace(/-/g, '/') + ' GMT+8').getTime(); + var v = new Date(value.replace(/-/g, '/') + ' GMT+8').getTime(); + if (fc.term === 'eq') { + if (v === tv) { + color = fc[type]; + flag = true; + } + } + else if (fc.term === 'not_eq') { + if (v !== tv) { + color = fc[type]; + flag = true; + } + } + else if (fc.term === 'lt') { + if (v < tv) { + color = fc[type]; + flag = true; + } + } + else if (fc.term === 'gt') { + if (v > tv) { + color = fc[type]; + flag = true; + } + } + else if (fc.term === 'le') { + if (v <= tv) { + color = fc[type]; + flag = true; + } + } + else if (fc.term === 'ge') { + if (v >= tv) { + color = fc[type]; + flag = true; + } + } + else if (fc.term === 'default') { + color = fc[type]; + flag = true; + } + if (flag) { + break; + } + else if (i === field.conditions.length - 1) { + color = defaultColor; + } + } + } + return color; +} +exports.mappingColor = mappingColor; +function getFieldValueMap(view) { + var fieldValueMap = {}; + if (view.data && view.data.dynamicAssistLines && view.data.dynamicAssistLines.length > 0) { + view.data.dynamicAssistLines.forEach(function (ele) { + fieldValueMap[ele.summary + '-' + ele.fieldId] = ele.value; + }); + } + return fieldValueMap; +} +function getValue(field, filedValueMap, rowData) { + var _a; + if (field.summary === 'value') { + return rowData ? rowData[(_a = field.field) === null || _a === void 0 ? void 0 : _a.gisbiName] : undefined; + } + else { + return filedValueMap[field.summary + '-' + field.fieldId]; + } +} +function handleTableEmptyStrategy(chart) { + var _a, _b, _c; + var newData = (((_a = chart.data) === null || _a === void 0 ? void 0 : _a.tableRow) || []); + var intersectionArr = []; + var senior = util_1.parseJson(chart.senior); + var emptyDataStrategy = (_b = senior === null || senior === void 0 ? void 0 : senior.functionCfg) === null || _b === void 0 ? void 0 : _b.emptyDataStrategy; + if (!emptyDataStrategy) { + emptyDataStrategy = 'breakLine'; + } + var emptyDataFieldCtrl = (_c = senior === null || senior === void 0 ? void 0 : senior.functionCfg) === null || _c === void 0 ? void 0 : _c.emptyDataFieldCtrl; + if (emptyDataStrategy !== 'breakLine' && (emptyDataFieldCtrl === null || emptyDataFieldCtrl === void 0 ? void 0 : emptyDataFieldCtrl.length) && (newData === null || newData === void 0 ? void 0 : newData.length)) { + var deNames = lodash_es_1.keys(newData[0]); + intersectionArr = lodash_es_1.intersection(deNames, emptyDataFieldCtrl); + } + if (intersectionArr.length) { + newData = lodash_es_1.cloneDeep(newData); + var _loop_2 = function (i) { + for (var j = 0, tmp = intersectionArr.length; j < tmp; j++) { + var deName = intersectionArr[j]; + if (newData[i][deName] === null) { + if (emptyDataStrategy === 'setZero') { + newData[i][deName] = 0; + } + if (emptyDataStrategy === 'ignoreData') { + newData = lodash_es_1.filter(newData, function (_, index) { return index !== i; }); + break; + } + } + } + }; + for (var i = newData.length - 1; i >= 0; i--) { + _loop_2(i); + } + } + return newData; +} +exports.handleTableEmptyStrategy = handleTableEmptyStrategy; +var SortTooltip = /** @class */ (function (_super) { + __extends(SortTooltip, _super); + function SortTooltip() { + return _super !== null && _super.apply(this, arguments) || this; + } + SortTooltip.prototype.show = function (showOptions) { + var iconName = showOptions.iconName; + if (iconName) { + this.showSortTooltip(showOptions); + return; + } + _super.prototype.show.call(this, showOptions); + }; + SortTooltip.prototype.showSortTooltip = function (showOptions) { + var _a, _b, _c; + var position = showOptions.position, options = showOptions.options, meta = showOptions.meta, event = showOptions.event; + var enterable = s2_1.getTooltipDefaultOptions(options).enterable; + var _d = this.spreadsheet.options.tooltip || {}, autoAdjustBoundary = _d.autoAdjustBoundary, adjustPosition = _d.adjustPosition; + this.visible = true; + this.options = showOptions; + var container = this['getContainer'](); + // 用 vue 手动 patch + var vNode = vue_1.createVNode(TableTooltip_vue_1["default"], { + table: this.spreadsheet, + meta: meta + }); + this.spreadsheet.tooltip.container.innerHTML = ''; + var childElement = document.createElement('div'); + this.spreadsheet.tooltip.container.appendChild(childElement); + vue_1.render(vNode, childElement); + var _e = s2_1.getAutoAdjustPosition({ + spreadsheet: this.spreadsheet, + position: position, + tooltipContainer: container, + autoAdjustBoundary: autoAdjustBoundary + }), x = _e.x, y = _e.y; + this.position = (_a = adjustPosition === null || adjustPosition === void 0 ? void 0 : adjustPosition({ position: { x: x, y: y }, event: event })) !== null && _a !== void 0 ? _a : { + x: x, + y: y + }; + s2_1.setTooltipContainerStyle(container, { + style: { + left: ((_b = this.position) === null || _b === void 0 ? void 0 : _b.x) + "px", + top: ((_c = this.position) === null || _c === void 0 ? void 0 : _c.y) + "px", + pointerEvents: enterable ? 'all' : 'none', + zIndex: 9999, + position: 'absolute', + color: 'black', + background: 'white', + fontSize: '16px' + }, + visible: true + }); + }; + return SortTooltip; +}(s2_1.BaseTooltip)); +exports.SortTooltip = SortTooltip; +var SORT_DEFAULT = ''; +var SORT_UP = ''; +var SORT_DOWN = ''; +function svg2Base64(svg) { + return "data:image/svg+xml;charset=utf-8;base64," + btoa(svg); +} +function configHeaderInteraction(chart, option) { + var _a = util_1.parseJson(chart.customAttr).tableHeader, tableHeaderFontColor = _a.tableHeaderFontColor, tableHeaderSort = _a.tableHeaderSort; + if (!tableHeaderSort) { + return; + } + var iconColor = tableHeaderFontColor !== null && tableHeaderFontColor !== void 0 ? tableHeaderFontColor : '#666'; + var sortDefault = svg2Base64(SORT_DEFAULT.replace('{fill}', iconColor)); + var sortUp = svg2Base64(SORT_UP.replace('{fill}', iconColor)); + var sortDown = svg2Base64(SORT_DOWN.replace('{fill}', iconColor)); + // 防止缓存 + var randomSuffix = Math.random(); + var sortIconMap = { + asc: "customSortUp" + randomSuffix, + desc: "customSortDown" + randomSuffix + }; + option.customSVGIcons = [ + { + name: "customSortDefault" + randomSuffix, + svg: sortDefault + }, + { + name: "customSortUp" + randomSuffix, + svg: sortUp + }, + { + name: "customSortDown" + randomSuffix, + svg: sortDown + } + ]; + option.headerActionIcons = [ + { + iconNames: [ + "customSortDefault" + randomSuffix, + "customSortUp" + randomSuffix, + "customSortDown" + randomSuffix + ], + belongsCell: 'colCell', + displayCondition: function (meta, iconName) { + if (meta.field === s2_1.SERIES_NUMBER_FIELD) { + return false; + } + // 分组 + if (meta.colIndex === -1) { + return false; + } + var sortMethodMap = meta.spreadsheet.store.get('sortMethodMap'); + var sortType = sortMethodMap === null || sortMethodMap === void 0 ? void 0 : sortMethodMap[meta.field]; + if (sortType) { + return iconName === sortIconMap[sortType]; + } + return iconName === "customSortDefault" + randomSuffix; + }, + onClick: function (props) { + var _a; + var meta = props.meta, event = props.event; + meta.spreadsheet.showTooltip(__assign({ position: { + x: event.clientX, + y: event.clientY + }, event: event }, props)); + var parent = document.getElementById(chart.container); + if ((_a = parent === null || parent === void 0 ? void 0 : parent.childNodes) === null || _a === void 0 ? void 0 : _a.length) { + var child = Array.from(parent.childNodes) + .filter(function (node) { return node.nodeType === s2_1.Node.ELEMENT_NODE; }) + .find(function (node) { return node.classList.contains('antv-s2-tooltip-container'); }); + if (child) { + var left = child.offsetLeft + child.clientWidth; + if (left > parent.offsetWidth) { + var newLeft = parent.offsetWidth - child.clientWidth - 10; + child.style.left = newLeft + "px"; + } + } + } + } + } + ]; +} +exports.configHeaderInteraction = configHeaderInteraction; +function configTooltip(chart, option) { + var tooltip = util_1.parseJson(chart.customAttr).tooltip; + var textFontFamily = chart.fontFamily ? chart.fontFamily : s2_1.FONT_FAMILY; + option.tooltip = __assign(__assign({}, option.tooltip), { style: { + background: tooltip.backgroundColor, + fontSize: tooltip.fontSize + 'px', + fontFamily: textFontFamily, + color: tooltip.color, + boxShadow: 'rgba(0, 0, 0, 0.1) 0px 4px 8px 0px', + borderRadius: '3px', + padding: '4px 12px', + opacity: 0.95, + position: 'absolute' + }, adjustPosition: function (_a) { + var event = _a.event; + return getTooltipPosition(event); + } }); +} +exports.configTooltip = configTooltip; +function copyContent(s2Instance, event, fieldMeta) { + var _a; + event.preventDefault(); + var cell = s2Instance.getCell(event.target); + var valueField = cell.getMeta().valueField; + var cellMeta = cell.getMeta(); + var selectState = s2Instance.interaction.getState(); + var content = ''; + // 多选 + if (selectState.stateName === s2_1.InteractionStateName.SELECTED) { + var cells = selectState.cells; + if (!(cells === null || cells === void 0 ? void 0 : cells.length)) { + return; + } + if (cells.length === 1) { + var curCell = cells[0]; + if (cell.getMeta().id === curCell.id) { + var cellMeta_1 = cell.getMeta(); + var value = (_a = cellMeta_1.data) === null || _a === void 0 ? void 0 : _a[cellMeta_1.valueField]; + var metaObj = lodash_es_1.find(fieldMeta, function (m) { return m.field === cellMeta_1.valueField; }); + var fieldVal = value === null || value === void 0 ? void 0 : value.toString(); + if (metaObj) { + fieldVal = metaObj.formatter(value); + } + util_1.copyString(fieldVal, true); + } + s2Instance.interaction.clearState(); + return; + } + var brushSelection = s2Instance.interaction.interactions.get(s2_1.InteractionName.BRUSH_SELECTION); + var selectedCells = brushSelection.getScrollBrushRangeCells(cells); + selectedCells.sort(function (a, b) { + var aMeta = a.getMeta(); + var bMeta = b.getMeta(); + if (aMeta.rowIndex !== bMeta.rowIndex) { + return aMeta.rowIndex - bMeta.rowIndex; + } + return aMeta.colIndex - bMeta.colIndex; + }); + // 点击已选的就复制,未选的就忽略 + var validClick_1 = false; + var matrix_1 = selectedCells.reduce(function (p, n) { + if (n.getMeta().colIndex === cellMeta.colIndex && + n.getMeta().rowIndex === cellMeta.rowIndex) { + validClick_1 = true; + } + var arr = p[n.getMeta().rowIndex]; + if (!arr) { + p[n.getMeta().rowIndex] = [n]; + } + else { + arr.push(n); + } + return p; + }, {}); + if (validClick_1) { + lodash_es_1.keys(matrix_1).forEach(function (k) { + var arr = matrix_1[k]; + arr.forEach(function (cell, index) { + var _a; + var cellMeta = cell.getMeta(); + var value = (_a = cellMeta.data) === null || _a === void 0 ? void 0 : _a[cellMeta.valueField]; + var metaObj = lodash_es_1.find(fieldMeta, function (m) { return m.field === cellMeta.valueField; }); + var fieldVal = value === null || value === void 0 ? void 0 : value.toString(); + if (metaObj) { + fieldVal = metaObj.formatter(value); + } + if (fieldVal === undefined || fieldVal === null) { + fieldVal = ''; + } + if (index !== arr.length - 1) { + fieldVal += '\t'; + } + content += fieldVal; + }); + content = content + '\n'; + }); + if (content) { + util_1.copyString(content, true); + } + } + s2Instance.interaction.clearState(); + return; + } + // 单元格 + if (cellMeta === null || cellMeta === void 0 ? void 0 : cellMeta.data) { + var value = cellMeta.data[valueField]; + var metaObj = lodash_es_1.find(fieldMeta, function (m) { return m.field === valueField; }); + content = value === null || value === void 0 ? void 0 : value.toString(); + if (metaObj) { + content = metaObj.formatter(value); + } + } + else { + // 列头&行头 + var fieldMap = fieldMeta === null || fieldMeta === void 0 ? void 0 : fieldMeta.reduce(function (p, n) { + p[n.field] = n.name; + return p; + }, {}); + content = cellMeta.value; + if (fieldMap === null || fieldMap === void 0 ? void 0 : fieldMap[content]) { + content = fieldMap[content]; + } + } + if (content) { + util_1.copyString(content, true); + } +} +exports.copyContent = copyContent; +function getTooltipPosition(event) { + var s2Instance = event.s2Instance; + var x = event.x, y = event.y; + var result = { x: x + 15, y: y }; + if (!s2Instance) { + return result; + } + var _a = s2Instance.getCanvasElement().getBoundingClientRect(), height = _a.height, width = _a.width; + var _b = s2Instance.tooltip.getContainer(), offsetHeight = _b.offsetHeight, offsetWidth = _b.offsetWidth; + if (offsetWidth > width) { + result.x = 0; + } + if (offsetHeight > height) { + result.y = 0; + } + if (!(result.x || result.y)) { + return result; + } + if (result.x && result.x + offsetWidth > width) { + result.x -= result.x + offsetWidth - width; + } + if (result.y) { + if (result.y > offsetHeight) { + if (result.y - offsetHeight >= 15) { + result.y -= offsetHeight + 15; + } + else { + result.y = 0; + } + } + else { + result.y += 15; + } + } + return result; +} +function exportGridPivot(instance, chart) { + var _a, _b, _c, _d, _e, _f; + return __awaiter(this, void 0, void 0, function () { + var layoutResult, _g, meta, fields, rowLength, colLength, colNums, workbook, worksheet, metaMap, rowLeafNodes, rowsHierarchy, rowNodes, maxColIndex, notLeafNodeHeightMap, getNodeStartRowIndex, colLeafNodes, colNodes, colsHierarchy, maxColHeight, notLeafNodeWidthMap, getNodeStartColIndex, rowIndex, colIndex, dataCellMeta, fieldValue, meta_1, cell, value, buffer, dataBlob; + return __generator(this, function (_h) { + switch (_h.label) { + case 0: + layoutResult = instance.facet.layoutResult; + _g = instance.dataCfg, meta = _g.meta, fields = _g.fields; + rowLength = ((_a = fields === null || fields === void 0 ? void 0 : fields.rows) === null || _a === void 0 ? void 0 : _a.length) || 0; + colLength = ((_b = fields === null || fields === void 0 ? void 0 : fields.columns) === null || _b === void 0 ? void 0 : _b.length) || 0; + colNums = layoutResult.colLeafNodes.length + rowLength; + if (colNums > 16384) { + element_plus_secondary_1.ElMessage.warning(i18nt('chart.pivot_export_invalid_col_exceed')); + return [2 /*return*/]; + } + workbook = new exceljs_1["default"].Workbook(); + worksheet = workbook.addWorksheet(i18nt('chart.chart_data')); + metaMap = meta === null || meta === void 0 ? void 0 : meta.reduce(function (p, n) { + if (n.field) { + p[n.field] = n; + } + return p; + }, {}); + // 角头 + (_c = fields.columns) === null || _c === void 0 ? void 0 : _c.forEach(function (column, index) { + var _a, _b; + var cell = worksheet.getCell(index + 1, 1); + cell.value = (_b = (_a = metaMap[column]) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : column; + cell.alignment = { vertical: 'middle', horizontal: 'center' }; + if (rowLength >= 2) { + worksheet.mergeCells(index + 1, 1, index + 1, rowLength); + } + cell.border = { + right: { style: 'thick', color: { argb: '00000000' } } + }; + }); + (_d = fields === null || fields === void 0 ? void 0 : fields.rows) === null || _d === void 0 ? void 0 : _d.forEach(function (row, index) { + var _a, _b; + var cell = worksheet.getCell(colLength + 1, index + 1); + cell.value = (_b = (_a = metaMap[row]) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : row; + cell.alignment = { vertical: 'middle', horizontal: 'center' }; + cell.border = { + bottom: { style: 'thick', color: { argb: '00000000' } } + }; + if (index === fields.rows.length - 1) { + cell.border.right = { style: 'thick', color: { argb: '00000000' } }; + } + }); + rowLeafNodes = layoutResult.rowLeafNodes, rowsHierarchy = layoutResult.rowsHierarchy, rowNodes = layoutResult.rowNodes; + maxColIndex = rowsHierarchy.maxLevel + 1; + notLeafNodeHeightMap = {}; + rowLeafNodes.forEach(function (node) { + var _a; + // 行头的高度由子节点相加决定,也就是行头子节点中包含的叶子节点数量 + var curNode = node.parent; + while (curNode) { + var height = (_a = notLeafNodeHeightMap[curNode.id]) !== null && _a !== void 0 ? _a : 0; + notLeafNodeHeightMap[curNode.id] = height + 1; + curNode = curNode.parent; + } + var rowIndex = node.rowIndex; + var writeRowIndex = rowIndex + 1 + colLength + 1; + var writeColIndex = node.level + 1; + var cell = worksheet.getCell(writeRowIndex, writeColIndex); + cell.value = node.label; + cell.alignment = { vertical: 'middle', horizontal: 'center' }; + if (writeColIndex < maxColIndex) { + worksheet.mergeCells(writeRowIndex, writeColIndex, writeRowIndex, maxColIndex); + } + cell.border = { + right: { style: 'thick', color: { argb: '00000000' } } + }; + }); + getNodeStartRowIndex = function (node) { + var _a; + if (!((_a = node.children) === null || _a === void 0 ? void 0 : _a.length)) { + return node.rowIndex + 1; + } + else { + return getNodeStartRowIndex(node.children[0]); + } + }; + rowNodes === null || rowNodes === void 0 ? void 0 : rowNodes.forEach(function (node) { + if (node.isLeaf) { + return; + } + var rowIndex = getNodeStartRowIndex(node); + var height = notLeafNodeHeightMap[node.id]; + var writeRowIndex = rowIndex + colLength + 1; + var mergeColCount = node.children[0].level - node.level; + var value = node.label; + var cell = worksheet.getCell(writeRowIndex, node.level + 1); + cell.value = value; + cell.alignment = { vertical: 'middle', horizontal: 'center' }; + if (mergeColCount > 1 || height > 1) { + worksheet.mergeCells(writeRowIndex, node.level + 1, writeRowIndex + height - 1, node.level + mergeColCount); + } + }); + colLeafNodes = layoutResult.colLeafNodes, colNodes = layoutResult.colNodes, colsHierarchy = layoutResult.colsHierarchy; + maxColHeight = colsHierarchy.maxLevel + 1; + notLeafNodeWidthMap = {}; + colLeafNodes.forEach(function (node) { + var _a, _b; + // 列头的宽度由子节点相加决定,也就是列头子节点中包含的叶子节点数量 + var curNode = node.parent; + while (curNode) { + var width = (_a = notLeafNodeWidthMap[curNode.id]) !== null && _a !== void 0 ? _a : 0; + notLeafNodeWidthMap[curNode.id] = width + 1; + curNode = curNode.parent; + } + var colIndex = node.colIndex; + var writeRowIndex = node.level + 1; + var writeColIndex = colIndex + 1 + rowLength; + var cell = worksheet.getCell(writeRowIndex, writeColIndex); + var value = node.label; + if (node.field === '$$extra$$' && ((_b = metaMap[value]) === null || _b === void 0 ? void 0 : _b.name)) { + value = metaMap[value].name; + } + cell.value = value; + cell.alignment = { vertical: 'middle', horizontal: 'center' }; + if (writeRowIndex < maxColHeight) { + worksheet.mergeCells(writeRowIndex, writeColIndex, maxColHeight, writeColIndex); + } + cell.border = { + bottom: { style: 'thick', color: { argb: '00000000' } } + }; + }); + getNodeStartColIndex = function (node) { + var _a; + if (!((_a = node.children) === null || _a === void 0 ? void 0 : _a.length)) { + return node.colIndex + 1; + } + else { + return getNodeStartColIndex(node.children[0]); + } + }; + colNodes.forEach(function (node) { + if (node.isLeaf) { + return; + } + var colIndex = getNodeStartColIndex(node); + var width = notLeafNodeWidthMap[node.id]; + var writeRowIndex = node.level + 1; + var mergeRowCount = node.children[0].level - node.level; + var value = node.label; + var writeColIndex = colIndex + rowLength; + var cell = worksheet.getCell(writeRowIndex, writeColIndex); + cell.value = value; + cell.alignment = { vertical: 'middle', horizontal: 'center' }; + if (mergeRowCount > 1 || width > 1) { + worksheet.mergeCells(writeRowIndex, writeColIndex, writeRowIndex + mergeRowCount - 1, writeColIndex + width - 1); + } + }); + // 单元格数据 + for (rowIndex = 0; rowIndex < rowLeafNodes.length; rowIndex++) { + for (colIndex = 0; colIndex < colLeafNodes.length; colIndex++) { + dataCellMeta = layoutResult.getCellMeta(rowIndex, colIndex); + fieldValue = dataCellMeta.fieldValue; + if (fieldValue === 0 || fieldValue) { + meta_1 = metaMap[dataCellMeta.valueField]; + cell = worksheet.getCell(rowIndex + maxColHeight + 1, rowLength + colIndex + 1); + value = ((_e = meta_1 === null || meta_1 === void 0 ? void 0 : meta_1.formatter) === null || _e === void 0 ? void 0 : _e.call(meta_1, fieldValue)) || fieldValue; + cell.alignment = { vertical: 'middle', horizontal: 'center' }; + cell.value = isNumeric(value) ? parseFloat(value) : value; + } + } + } + return [4 /*yield*/, workbook.xlsx.writeBuffer()]; + case 1: + buffer = _h.sent(); + dataBlob = new Blob([buffer], { + type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8' + }); + file_saver_1.saveAs(dataBlob, ((_f = chart.title) !== null && _f !== void 0 ? _f : '透视表') + ".xlsx"); + return [2 /*return*/]; + } + }); + }); +} +exports.exportGridPivot = exportGridPivot; +function exportRowQuotaGridPivot(instance, chart) { + var _a, _b, _c, _d, _e, _f; + return __awaiter(this, void 0, void 0, function () { + var layoutResult, _g, meta, fields, rowLength, colLength, colNums, workbook, worksheet, metaMap, quotaColLabel, quotaColHeadCell, rowLeafNodes, rowNodes, notLeafNodeHeightMap, getNodeStartRowIndex, colLeafNodes, colNodes, colsHierarchy, maxColHeight, notLeafNodeWidthMap, getNodeStartColIndex, rowIndex, colIndex, dataCellMeta, fieldValue, meta_2, cell, value, buffer, dataBlob; + return __generator(this, function (_h) { + switch (_h.label) { + case 0: + layoutResult = instance.facet.layoutResult; + _g = instance.dataCfg, meta = _g.meta, fields = _g.fields; + rowLength = ((_a = fields === null || fields === void 0 ? void 0 : fields.rows) === null || _a === void 0 ? void 0 : _a.length) || 0; + colLength = ((_b = fields === null || fields === void 0 ? void 0 : fields.columns) === null || _b === void 0 ? void 0 : _b.length) || 0; + colNums = layoutResult.colLeafNodes.length + rowLength; + if (colNums > 16384) { + element_plus_secondary_1.ElMessage.warning(i18nt('chart.pivot_export_invalid_col_exceed')); + return [2 /*return*/]; + } + workbook = new exceljs_1["default"].Workbook(); + worksheet = workbook.addWorksheet(i18nt('chart.chart_data')); + metaMap = meta === null || meta === void 0 ? void 0 : meta.reduce(function (p, n) { + if (n.field) { + p[n.field] = n; + } + return p; + }, {}); + // 角头 + if (colLength > 1) { + fields.columns.forEach(function (column, index) { + var _a, _b; + if (index >= colLength - 1) { + return; + } + var cell = worksheet.getCell(index + 1, 1); + cell.value = (_b = (_a = metaMap[column]) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : column; + cell.alignment = { vertical: 'middle', horizontal: 'center' }; + cell.border = { + right: { style: 'thick', color: { argb: '00000000' } } + }; + worksheet.mergeCells(index + 1, 1, index + 1, rowLength + 1); + }); + } + (_c = fields === null || fields === void 0 ? void 0 : fields.rows) === null || _c === void 0 ? void 0 : _c.forEach(function (row, index) { + var _a, _b; + var cell = worksheet.getCell(colLength === 0 ? 1 : colLength, index + 1); + cell.value = (_b = (_a = metaMap[row]) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : row; + cell.alignment = { vertical: 'middle', horizontal: 'center' }; + cell.border = { bottom: { style: 'thick', color: { argb: '00000000' } } }; + }); + quotaColLabel = (_d = chart.customAttr.basicStyle.quotaColLabel) !== null && _d !== void 0 ? _d : t('dataset.value'); + quotaColHeadCell = worksheet.getCell(colLength === 0 ? 1 : colLength, rowLength + 1); + quotaColHeadCell.value = quotaColLabel; + quotaColHeadCell.alignment = { vertical: 'middle', horizontal: 'center' }; + quotaColHeadCell.border = { + bottom: { style: 'thick', color: { argb: '00000000' } }, + right: { style: 'thick', color: { argb: '00000000' } } + }; + rowLeafNodes = layoutResult.rowLeafNodes, rowNodes = layoutResult.rowNodes; + notLeafNodeHeightMap = {}; + rowLeafNodes.forEach(function (node) { + var _a, _b; + // 行头的高度由子节点相加决定,也就是行头子节点中包含的叶子节点数量 + var curNode = node.parent; + while (curNode) { + var height = (_a = notLeafNodeHeightMap[curNode.id]) !== null && _a !== void 0 ? _a : 0; + notLeafNodeHeightMap[curNode.id] = height + 1; + curNode = curNode.parent; + } + var rowIndex = node.rowIndex; + var writeRowIndex = rowIndex + 2 + (colLength === 0 ? 1 : colLength - 1); + var writeColIndex = node.level + 1; + var cell = worksheet.getCell(writeRowIndex, writeColIndex); + var value = node.label; + if (node.field === '$$extra$$' && ((_b = metaMap[value]) === null || _b === void 0 ? void 0 : _b.name)) { + value = metaMap[value].name; + } + cell.value = value; + cell.alignment = { vertical: 'middle', horizontal: 'center' }; + cell.border = { + right: { style: 'thick', color: { argb: '00000000' } } + }; + }); + getNodeStartRowIndex = function (node) { + var _a; + if (!((_a = node.children) === null || _a === void 0 ? void 0 : _a.length)) { + return node.rowIndex + 1; + } + else { + return getNodeStartRowIndex(node.children[0]); + } + }; + rowNodes === null || rowNodes === void 0 ? void 0 : rowNodes.forEach(function (node) { + if (node.isLeaf) { + return; + } + var rowIndex = getNodeStartRowIndex(node); + var height = notLeafNodeHeightMap[node.id]; + var writeRowIndex = rowIndex + 1 + (colLength === 0 ? 1 : colLength - 1); + var mergeColCount = node.children[0].level - node.level; + var cell = worksheet.getCell(writeRowIndex, node.level + 1); + cell.value = node.label; + cell.alignment = { vertical: 'middle', horizontal: 'center' }; + if (mergeColCount > 1 || height > 1) { + worksheet.mergeCells(writeRowIndex, node.level + 1, writeRowIndex + height - 1, node.level + mergeColCount); + } + }); + colLeafNodes = layoutResult.colLeafNodes, colNodes = layoutResult.colNodes, colsHierarchy = layoutResult.colsHierarchy; + maxColHeight = colsHierarchy.maxLevel + 1; + notLeafNodeWidthMap = {}; + colLeafNodes.forEach(function (node) { + var _a; + // 列头的宽度由子节点相加决定,也就是列头子节点中包含的叶子节点数量 + var curNode = node.parent; + while (curNode) { + var width = (_a = notLeafNodeWidthMap[curNode.id]) !== null && _a !== void 0 ? _a : 0; + notLeafNodeWidthMap[curNode.id] = width + 1; + curNode = curNode.parent; + } + var colIndex = node.colIndex; + var writeRowIndex = node.level + 1; + var writeColIndex = colIndex + rowLength + 2; + var cell = worksheet.getCell(writeRowIndex, writeColIndex); + var value = node.label; + cell.value = value; + cell.alignment = { vertical: 'middle', horizontal: 'center' }; + if (writeRowIndex < maxColHeight) { + worksheet.mergeCells(writeRowIndex, writeColIndex, maxColHeight, writeColIndex); + } + cell.border = { + bottom: { style: 'thick', color: { argb: '00000000' } } + }; + }); + getNodeStartColIndex = function (node) { + var _a; + if (!((_a = node.children) === null || _a === void 0 ? void 0 : _a.length)) { + return node.colIndex + 1; + } + else { + return getNodeStartColIndex(node.children[0]); + } + }; + colNodes.forEach(function (node) { + if (node.isLeaf) { + return; + } + var colIndex = getNodeStartColIndex(node); + var width = notLeafNodeWidthMap[node.id]; + var writeRowIndex = node.level + 1; + var value = node.label; + var writeColIndex = colIndex + rowLength + 1; + var cell = worksheet.getCell(writeRowIndex, writeColIndex); + cell.value = value; + cell.alignment = { vertical: 'middle', horizontal: 'center' }; + if (width > 1) { + worksheet.mergeCells(writeRowIndex, writeColIndex, writeRowIndex, writeColIndex + width - 1); + } + }); + // 单元格数据 + for (rowIndex = 0; rowIndex < rowLeafNodes.length; rowIndex++) { + for (colIndex = 0; colIndex < colLeafNodes.length; colIndex++) { + dataCellMeta = layoutResult.getCellMeta(rowIndex, colIndex); + fieldValue = dataCellMeta.fieldValue; + if (fieldValue === 0 || fieldValue) { + meta_2 = metaMap[dataCellMeta.valueField]; + cell = worksheet.getCell(rowIndex + maxColHeight + 1, rowLength + colIndex + 2); + value = ((_e = meta_2 === null || meta_2 === void 0 ? void 0 : meta_2.formatter) === null || _e === void 0 ? void 0 : _e.call(meta_2, fieldValue)) || fieldValue; + cell.alignment = { vertical: 'middle', horizontal: 'center' }; + cell.value = isNumeric(value) ? parseFloat(value) : value; + } + } + } + return [4 /*yield*/, workbook.xlsx.writeBuffer()]; + case 1: + buffer = _h.sent(); + dataBlob = new Blob([buffer], { + type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8' + }); + file_saver_1.saveAs(dataBlob, ((_f = chart.title) !== null && _f !== void 0 ? _f : '透视表') + ".xlsx"); + return [2 /*return*/]; + } + }); + }); +} +exports.exportRowQuotaGridPivot = exportRowQuotaGridPivot; +function exportTreePivot(instance, chart) { + var _a, _b, _c, _d, _e; + return __awaiter(this, void 0, void 0, function () { + var layoutResult, _f, meta, fields, colLength, workbook, worksheet, metaMap, maxColHeight, rowName, cell, rowLeafNodes, notLeafNodeWidthMap, colLeafNodes, colNodes, getNodeStartIndex, rowIndex, colIndex, dataCellMeta, fieldValue, meta_3, cell_1, value, buffer, dataBlob; + return __generator(this, function (_g) { + switch (_g.label) { + case 0: + layoutResult = instance.facet.layoutResult; + if (layoutResult.colLeafNodes.length + 1 > 16384) { + element_plus_secondary_1.ElMessage.warning(i18nt('chart.pivot_export_invalid_col_exceed')); + return [2 /*return*/]; + } + _f = instance.dataCfg, meta = _f.meta, fields = _f.fields; + colLength = ((_a = fields === null || fields === void 0 ? void 0 : fields.columns) === null || _a === void 0 ? void 0 : _a.length) || 0; + workbook = new exceljs_1["default"].Workbook(); + worksheet = workbook.addWorksheet(i18nt('chart.chart_data')); + metaMap = meta === null || meta === void 0 ? void 0 : meta.reduce(function (p, n) { + if (n.field) { + p[n.field] = n; + } + return p; + }, {}); + // 角头 + (_b = fields.columns) === null || _b === void 0 ? void 0 : _b.forEach(function (column, index) { + var _a, _b; + var cell = worksheet.getCell(index + 1, 1); + cell.value = (_b = (_a = metaMap[column]) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : column; + cell.alignment = { vertical: 'middle', horizontal: 'center' }; + cell.border = { + right: { style: 'thick', color: { argb: '00000000' } } + }; + }); + maxColHeight = layoutResult.colsHierarchy.maxLevel + 1; + rowName = (_c = fields === null || fields === void 0 ? void 0 : fields.rows) === null || _c === void 0 ? void 0 : _c.map(function (row) { var _a, _b; return (_b = (_a = metaMap[row]) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : row; }).join('/'); + cell = worksheet.getCell(colLength + 1, 1); + cell.value = rowName; + cell.alignment = { vertical: 'middle', horizontal: 'center' }; + cell.border = { + right: { style: 'thick', color: { argb: '00000000' } }, + bottom: { style: 'thick', color: { argb: '00000000' } } + }; + rowLeafNodes = layoutResult.rowLeafNodes; + rowLeafNodes.forEach(function (node, index) { + var cell = worksheet.getCell(maxColHeight + index + 1, 1); + cell.value = lodash_es_1.repeat(' ', node.level) + node.label; + cell.alignment = { vertical: 'middle', horizontal: 'left' }; + cell.border = { + right: { style: 'thick', color: { argb: '00000000' } } + }; + }); + notLeafNodeWidthMap = {}; + colLeafNodes = layoutResult.colLeafNodes; + colLeafNodes.forEach(function (node) { + var _a, _b; + var curNode = node.parent; + while (curNode) { + var width = (_a = notLeafNodeWidthMap[curNode.id]) !== null && _a !== void 0 ? _a : 0; + notLeafNodeWidthMap[curNode.id] = width + 1; + curNode = curNode.parent; + } + var colIndex = node.colIndex; + var writeRowIndex = node.level + 1; + var writeColIndex = colIndex + 1 + 1; + var cell = worksheet.getCell(writeRowIndex, writeColIndex); + var value = node.label; + if (node.field === '$$extra$$' && ((_b = metaMap[value]) === null || _b === void 0 ? void 0 : _b.name)) { + value = metaMap[value].name; + } + cell.value = value; + cell.alignment = { vertical: 'middle', horizontal: 'center' }; + if (writeRowIndex < maxColHeight) { + worksheet.mergeCells(writeRowIndex, writeColIndex, maxColHeight, writeColIndex); + } + cell.border = { + bottom: { style: 'thick', color: { argb: '00000000' } } + }; + }); + colNodes = layoutResult.colNodes; + getNodeStartIndex = function (node) { + var _a; + if (!((_a = node.children) === null || _a === void 0 ? void 0 : _a.length)) { + return node.colIndex + 1; + } + else { + return getNodeStartIndex(node.children[0]); + } + }; + colNodes.forEach(function (node) { + if (node.isLeaf) { + return; + } + var colIndex = getNodeStartIndex(node); + var width = notLeafNodeWidthMap[node.id]; + var writeRowIndex = node.level + 1; + var mergeRowCount = node.children[0].level - node.level; + var writeColIndex = colIndex + 1; + var cell = worksheet.getCell(writeRowIndex, writeColIndex); + cell.value = node.label; + cell.alignment = { vertical: 'middle', horizontal: 'center' }; + if (mergeRowCount > 1 || width > 1) { + worksheet.mergeCells(writeRowIndex, writeColIndex, writeRowIndex + mergeRowCount - 1, writeColIndex + width - 1); + } + }); + // 单元格数据 + for (rowIndex = 0; rowIndex < rowLeafNodes.length; rowIndex++) { + for (colIndex = 0; colIndex < colLeafNodes.length; colIndex++) { + dataCellMeta = layoutResult.getCellMeta(rowIndex, colIndex); + fieldValue = dataCellMeta.fieldValue; + if (fieldValue === 0 || fieldValue) { + meta_3 = metaMap[dataCellMeta.valueField]; + cell_1 = worksheet.getCell(rowIndex + maxColHeight + 1, colIndex + 1 + 1); + value = ((_d = meta_3 === null || meta_3 === void 0 ? void 0 : meta_3.formatter) === null || _d === void 0 ? void 0 : _d.call(meta_3, fieldValue)) || fieldValue; + cell_1.alignment = { vertical: 'middle', horizontal: 'center' }; + cell_1.value = isNumeric(value) ? parseFloat(value) : value; + } + } + } + return [4 /*yield*/, workbook.xlsx.writeBuffer()]; + case 1: + buffer = _g.sent(); + dataBlob = new Blob([buffer], { + type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8' + }); + file_saver_1.saveAs(dataBlob, ((_e = chart.title) !== null && _e !== void 0 ? _e : '透视表') + ".xlsx"); + return [2 /*return*/]; + } + }); + }); +} +exports.exportTreePivot = exportTreePivot; +function exportRowQuotaTreePivot(instance, chart) { + var _a, _b, _c, _d, _e, _f; + return __awaiter(this, void 0, void 0, function () { + var layoutResult, _g, meta, fields, colLength, workbook, worksheet, metaMap, quotaColLabel, maxColHeight, rowName, cell, rowLeafNodes, notLeafNodeWidthMap, colLeafNodes, colNodes, getNodeStartIndex, rowIndex, colIndex, dataCellMeta, fieldValue, meta_4, cell_2, value, buffer, dataBlob; + return __generator(this, function (_h) { + switch (_h.label) { + case 0: + layoutResult = instance.facet.layoutResult; + if (layoutResult.colLeafNodes.length + 1 > 16384) { + element_plus_secondary_1.ElMessage.warning(i18nt('chart.pivot_export_invalid_col_exceed')); + return [2 /*return*/]; + } + _g = instance.dataCfg, meta = _g.meta, fields = _g.fields; + colLength = ((_a = fields === null || fields === void 0 ? void 0 : fields.columns) === null || _a === void 0 ? void 0 : _a.length) || 0; + workbook = new exceljs_1["default"].Workbook(); + worksheet = workbook.addWorksheet(i18nt('chart.chart_data')); + metaMap = meta === null || meta === void 0 ? void 0 : meta.reduce(function (p, n) { + if (n.field) { + p[n.field] = n; + } + return p; + }, {}); + // 角头 + (_b = fields.columns) === null || _b === void 0 ? void 0 : _b.forEach(function (column, index) { + var _a, _b; + if (index >= fields.columns.length - 1) { + return; + } + var cell = worksheet.getCell(index + 1, 1); + cell.value = (_b = (_a = metaMap[column]) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : column; + cell.alignment = { vertical: 'middle', horizontal: 'center' }; + cell.border = { + right: { style: 'thick', color: { argb: '00000000' } } + }; + }); + quotaColLabel = (_c = chart.customAttr.basicStyle.quotaColLabel) !== null && _c !== void 0 ? _c : t('dataset.value'); + maxColHeight = layoutResult.colsHierarchy.maxLevel + 1; + rowName = (_d = fields === null || fields === void 0 ? void 0 : fields.rows) === null || _d === void 0 ? void 0 : _d.map(function (row) { var _a, _b; return (_b = (_a = metaMap[row]) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : row; }).concat(quotaColLabel).join('/'); + cell = worksheet.getCell(colLength, 1); + cell.value = rowName; + cell.alignment = { vertical: 'middle', horizontal: 'center' }; + cell.border = { + right: { style: 'thick', color: { argb: '00000000' } }, + bottom: { style: 'thick', color: { argb: '00000000' } } + }; + rowLeafNodes = layoutResult.rowLeafNodes; + rowLeafNodes.forEach(function (node, index) { + var _a; + var cell = worksheet.getCell(maxColHeight + index + 1, 1); + var value = node.label; + if (node.field === '$$extra$$' && ((_a = metaMap[value]) === null || _a === void 0 ? void 0 : _a.name)) { + value = metaMap[value].name; + } + cell.value = lodash_es_1.repeat(' ', node.level) + value; + cell.alignment = { vertical: 'middle', horizontal: 'left' }; + cell.border = { + right: { style: 'thick', color: { argb: '00000000' } } + }; + }); + notLeafNodeWidthMap = {}; + colLeafNodes = layoutResult.colLeafNodes; + colLeafNodes.forEach(function (node) { + var _a; + var curNode = node.parent; + while (curNode) { + var width = (_a = notLeafNodeWidthMap[curNode.id]) !== null && _a !== void 0 ? _a : 0; + notLeafNodeWidthMap[curNode.id] = width + 1; + curNode = curNode.parent; + } + var colIndex = node.colIndex; + var writeRowIndex = node.level + 1; + var writeColIndex = colIndex + 2; + var cell = worksheet.getCell(writeRowIndex, writeColIndex); + cell.value = node.label; + cell.alignment = { vertical: 'middle', horizontal: 'center' }; + if (writeRowIndex < maxColHeight) { + worksheet.mergeCells(writeRowIndex, writeColIndex, maxColHeight, writeColIndex); + } + cell.border = { + bottom: { style: 'thick', color: { argb: '00000000' } } + }; + }); + colNodes = layoutResult.colNodes; + getNodeStartIndex = function (node) { + var _a; + if (!((_a = node.children) === null || _a === void 0 ? void 0 : _a.length)) { + return node.colIndex + 1; + } + else { + return getNodeStartIndex(node.children[0]); + } + }; + colNodes.forEach(function (node) { + if (node.isLeaf) { + return; + } + var colIndex = getNodeStartIndex(node); + var width = notLeafNodeWidthMap[node.id]; + var writeRowIndex = node.level + 1; + var writeColIndex = colIndex + 1; + var cell = worksheet.getCell(writeRowIndex, writeColIndex); + cell.value = node.label; + cell.alignment = { vertical: 'middle', horizontal: 'center' }; + if (width > 1) { + worksheet.mergeCells(writeRowIndex, writeColIndex, writeRowIndex, writeColIndex + width - 1); + } + }); + // 单元格数据 + for (rowIndex = 0; rowIndex < rowLeafNodes.length; rowIndex++) { + for (colIndex = 0; colIndex < colLeafNodes.length; colIndex++) { + dataCellMeta = layoutResult.getCellMeta(rowIndex, colIndex); + fieldValue = dataCellMeta.fieldValue; + if (fieldValue === 0 || fieldValue) { + meta_4 = metaMap[dataCellMeta.valueField]; + cell_2 = worksheet.getCell(rowIndex + maxColHeight + 1, colIndex + 2); + value = ((_e = meta_4 === null || meta_4 === void 0 ? void 0 : meta_4.formatter) === null || _e === void 0 ? void 0 : _e.call(meta_4, fieldValue)) || fieldValue; + cell_2.alignment = { vertical: 'middle', horizontal: 'center' }; + cell_2.value = isNumeric(value) ? parseFloat(value) : value; + } + } + } + return [4 /*yield*/, workbook.xlsx.writeBuffer()]; + case 1: + buffer = _h.sent(); + dataBlob = new Blob([buffer], { + type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8' + }); + file_saver_1.saveAs(dataBlob, ((_f = chart.title) !== null && _f !== void 0 ? _f : '透视表') + ".xlsx"); + return [2 /*return*/]; + } + }); + }); +} +exports.exportRowQuotaTreePivot = exportRowQuotaTreePivot; +function isNumeric(value) { + return /^[+-]?\d+(\.\d+)?$/.test(value); +} +function exportPivotExcel(instance, chart) { + var _a, _b; + return __awaiter(this, void 0, void 0, function () { + var fields, rowLength, valueLength, quotaPosition; + return __generator(this, function (_c) { + fields = instance.dataCfg.fields; + rowLength = ((_a = fields === null || fields === void 0 ? void 0 : fields.rows) === null || _a === void 0 ? void 0 : _a.length) || 0; + valueLength = ((_b = fields === null || fields === void 0 ? void 0 : fields.values) === null || _b === void 0 ? void 0 : _b.length) || 0; + if (!(rowLength && valueLength)) { + element_plus_secondary_1.ElMessage.warning(i18nt('chart.pivot_export_invalid_field')); + return [2 /*return*/]; + } + quotaPosition = chart.customAttr.basicStyle.quotaPosition; + if (chart.customAttr.basicStyle.tableLayoutMode !== 'tree') { + if (quotaPosition === 'row') { + exportRowQuotaGridPivot(instance, chart); + } + else { + exportGridPivot(instance, chart); + } + } + else { + if (quotaPosition === 'row') { + exportRowQuotaTreePivot(instance, chart); + } + else { + exportTreePivot(instance, chart); + } + } + return [2 /*return*/]; + }); + }); +} +exports.exportPivotExcel = exportPivotExcel; +function configMergeCells(chart, options, dataConfig) { + var _a; + var mergeCells = util_1.parseJson(chart.customAttr).tableCell.mergeCells; + var showIndex = util_1.parseJson(chart.customAttr).tableHeader.showIndex; + if (mergeCells) { + options.frozenColCount = 0; + options.frozenRowCount = 0; + var fields = chart.data.fields || []; + var fieldsMap_1 = fields.reduce(function (p, n) { + p[n.gisbiName] = n; + return p; + }, {}) || {}; + var quotaIndex_1 = dataConfig.meta.findIndex(function (m) { var _a; return ((_a = fieldsMap_1[m.field]) === null || _a === void 0 ? void 0 : _a.groupType) === 'q'; }); + var data_1 = (_a = chart.data) === null || _a === void 0 ? void 0 : _a.tableRow; + if (quotaIndex_1 === 0 || !(data_1 === null || data_1 === void 0 ? void 0 : data_1.length)) { + return; + } + var mergedColInfo_1 = [[[0, data_1.length - 1]]]; + var mergedCellsInfo_1 = []; + var axisToMerge = dataConfig.meta.filter(function (_, i) { return i < quotaIndex_1 || quotaIndex_1 === -1; }); + axisToMerge.forEach(function (a, i) { + var preMergedColInfo = mergedColInfo_1[i]; + var curMergedColInfo = []; + mergedColInfo_1.push(curMergedColInfo); + preMergedColInfo.forEach(function (range) { + var start = range[0], end = range[1]; + var lastVal = data_1[start][a.field]; + var lastIndex = start; + for (var index = start; index <= end; index++) { + var curVal = data_1[index][a.field]; + if (curVal !== lastVal || index === end) { + var curRange = index - lastIndex; + if (curRange > 1 || (index === end && curRange === 1 && lastVal === curVal)) { + var tmpMergeCells = []; + var textIndex = curRange % 2 === 1 ? (curRange - 1) / 2 : curRange / 2 - 1; + for (var j = 0; j < curRange; j++) { + tmpMergeCells.push({ + colIndex: showIndex ? i + 1 : i, + rowIndex: lastIndex + j, + showText: j === textIndex + }); + } + if (index === end && lastVal === curVal) { + tmpMergeCells.push({ + colIndex: showIndex ? i + 1 : i, + rowIndex: index, + showText: false + }); + } + mergedCellsInfo_1.push(tmpMergeCells); + curMergedColInfo.push([ + lastIndex, + index === end && lastVal === curVal ? index : index - 1 + ]); + } + lastVal = curVal; + lastIndex = index; + } + } + }); + }); + if (showIndex) { + var indexMergedCells = mergedCellsInfo_1.filter(function (cells) { return cells[0].colIndex === 1; }); + indexMergedCells.forEach(function (cells) { + var tmpCells = lodash_es_1.cloneDeep(cells); + tmpCells.forEach(function (cell) { + cell.colIndex = 0; + }); + mergedCellsInfo_1.unshift(tmpCells); + }); + } + options.mergedCellsInfo = mergedCellsInfo_1; + options.mergedCell = function (sheet, cells, meta) { + var _a; + if (showIndex && meta.colIndex === 0) { + meta.fieldValue = getRowIndex(mergedCellsInfo_1, meta); + } + meta.deFieldType = (_a = fieldsMap_1[meta.valueField]) === null || _a === void 0 ? void 0 : _a.deType; + return new CustomMergedCell(sheet, cells, meta); + }; + } +} +exports.configMergeCells = configMergeCells; +function getRowIndex(mergedCellsInfo, meta) { + if (!(mergedCellsInfo === null || mergedCellsInfo === void 0 ? void 0 : mergedCellsInfo.length)) { + return meta.rowIndex + 1; + } + var curRangeStartIndex = meta.rowIndex; + var lostCells = mergedCellsInfo.reduce(function (p, n) { + if (n[0].colIndex !== 0) { + return p; + } + var start = n[0].rowIndex; + var end = n[n.length - 1].rowIndex; + var lost = end - start; + if (meta.rowIndex >= start && meta.rowIndex <= end) { + curRangeStartIndex = start; + } + if (meta.rowIndex > end) { + return p + lost; + } + return p; + }, 0); + return curRangeStartIndex - lostCells + 1; +} +exports.getRowIndex = getRowIndex; +var CustomMergedCell = /** @class */ (function (_super) { + __extends(CustomMergedCell, _super); + function CustomMergedCell() { + return _super !== null && _super.apply(this, arguments) || this; + } + CustomMergedCell.prototype.drawBackgroundShape = function () { + var allPoints = s2_1.getPolygonPoints(this.cells); + // 处理条件样式,这里没有用透明度 + // 因为合并的单元格是单独的图层,透明度降低的话会显示底下未合并的单元格,需要单独处理被覆盖的单元格 + var fill = this.getBackgroundColor().backgroundColor; + var cellTheme = this.theme.dataCell.cell; + this.backgroundShape = s2_1.renderPolygon(this, { + points: allPoints, + stroke: cellTheme.horizontalBorderColor, + fill: fill, + lineHeight: cellTheme.horizontalBorderWidth + }); + }; + CustomMergedCell.prototype.drawTextShape = function () { + if (this.meta.deFieldType === 7) { + drawImage.apply(this); + } + else { + _super.prototype.drawTextShape.call(this); + } + }; + return CustomMergedCell; +}(s2_1.MergedCell)); +var CustomDataCell = /** @class */ (function (_super) { + __extends(CustomDataCell, _super); + function CustomDataCell() { + return _super !== null && _super.apply(this, arguments) || this; + } + /** + * 重写这个方法是为了处理底部的汇总行取消 hover 状态时设置 border 为 1, + * 这样会导致单元格隐藏横边边框失败,出现一条白线 + */ + CustomDataCell.prototype.hideInteractionShape = function () { + this.stateShapes.forEach(function (shape) { + s2_1.updateShapeAttr(shape, s2_1.SHAPE_STYLE_MAP.backgroundOpacity, 0); + s2_1.updateShapeAttr(shape, s2_1.SHAPE_STYLE_MAP.backgroundColor, 'transparent'); + s2_1.updateShapeAttr(shape, s2_1.SHAPE_STYLE_MAP.borderOpacity, 0); + s2_1.updateShapeAttr(shape, s2_1.SHAPE_STYLE_MAP.borderWidth, 0); + s2_1.updateShapeAttr(shape, s2_1.SHAPE_STYLE_MAP.borderColor, 'transparent'); + }); + }; + /** + * 重写绘制文本内容的方法 + * @protected + */ + CustomDataCell.prototype.drawTextShape = function () { + if (this.meta.autoWrap) { + drawTextShape(this, false); + } + else { + _super.prototype.drawTextShape.call(this); + } + }; + return CustomDataCell; +}(s2_1.TableDataCell)); +exports.CustomDataCell = CustomDataCell; +var CustomTableColCell = /** @class */ (function (_super) { + __extends(CustomTableColCell, _super); + function CustomTableColCell() { + return _super !== null && _super.apply(this, arguments) || this; + } + /** + * 重写是为了表头文本内容的换行 + * @protected + */ + CustomTableColCell.prototype.drawTextShape = function () { + if (this.meta.autoWrap) { + drawTextShape(this, true); + } + else { + _super.prototype.drawTextShape.call(this); + } + }; + return CustomTableColCell; +}(s2_1.TableColCell)); +exports.CustomTableColCell = CustomTableColCell; +/** + * 绘制文本 换行 + * @param cell + * @param isHeader + */ +var drawTextShape = function (cell, isHeader) { + var _a; + // 换行符 + var lineBreak = '\n'; + // 省略号 + var ellipsis = '...'; + // 用户配置的最大行数 + var maxLines = (_a = cell.meta.maxLines) !== null && _a !== void 0 ? _a : 1; + var placeholder = cell.spreadsheet.options.placeholder; + var emptyPlaceholder = s2_1.getEmptyPlaceholder(_this, placeholder); + // 单元格文本 + var formattedValue = cell.getFormattedFieldValue().formattedValue; + // 获取文本样式 + var textStyle = cell.getTextStyle(); + // 宽度能放几个字符,就放几个,放不下就换行 + var wrapText = getWrapText(formattedValue ? formattedValue === null || formattedValue === void 0 ? void 0 : formattedValue.toString() : emptyPlaceholder, textStyle, cell.meta.width, cell.spreadsheet); + var lines = wrapText.split(lineBreak); + var extraStyleFontSize = textStyle.fontSize; + // 不是表头,处理文本高度和换行 + if (!isHeader) { + var textHeight = getWrapTextHeight(wrapText.replaceAll(lineBreak, ''), textStyle, cell.spreadsheet, maxLines); + var lineCountInCell = Math.floor(cell.meta.height / textHeight); + var wrapTextArr = lines.slice(0, lineCountInCell); + // 根据行数调整换行后的文本内容 + wrapText = lineCountInCell < 1 ? ellipsis : wrapTextArr.join(lineBreak) || ellipsis; + var resultWrapArr = wrapText.split(lineBreak); + // 控制最大行数 + if (!wrapText.endsWith(ellipsis) && + (lines.length > maxLines || lines.length > lineCountInCell)) { + // 第一行的字符个数 + var firstLineStrNumber = resultWrapArr[0].length; + var temp = resultWrapArr.slice(0, Math.min(maxLines, lineCountInCell)); + // 修改最后一行的字符,按照第一行字符个数-1,修改最后一行的字符为... + temp[temp.length - 1] = temp[temp.length - 1].slice(0, firstLineStrNumber - 1) + ellipsis; + wrapText = temp.join(lineBreak); + } + if (wrapText === ellipsis) { + extraStyleFontSize = 12; + } + } + else { + var resultWrapArr = wrapText.split(lineBreak); + // 控制最大行数 + if (lines.length > maxLines) { + var temp = resultWrapArr.slice(0, maxLines); + // 第一行的字符个数 + var firstLineStrNumber = resultWrapArr[0].length; + // 修改最后一行的字符 + temp[temp.length - 1] = temp[temp.length - 1].slice(0, firstLineStrNumber - 1) + ellipsis; + wrapText = temp.join(lineBreak); + } + } + // 设置最终文本和其宽度 + cell.actualText = wrapText; + cell.actualTextWidth = cell.spreadsheet.measureTextWidth(wrapText, textStyle); + // 获取文本位置并渲染文本 + var position = cell.getTextPosition(); + // 绘制文本 + cell.textShape = s2_1.renderText(cell, [cell.textShape], position.x, position.y, wrapText, textStyle, { + fontSize: extraStyleFontSize + }); + // 将文本形状添加到形状数组 + cell.textShapes.push(cell.textShape); +}; +/** + * 计算表头高度 + * @param info 单元格信息 + * @param newChart + * @param tableHeader 表头配置 + * @param basicStyle 表格基础样式 + * @param layoutResult + */ +exports.calculateHeaderHeight = function (info, newChart, tableHeader, basicStyle, layoutResult) { + var _a; + if (tableHeader.showTableHeader === false) + return; + var ev = layoutResult || newChart.facet.layoutResult; + var maxLines = (_a = basicStyle.maxLines) !== null && _a !== void 0 ? _a : 1; + var textStyle = __assign({}, newChart.theme.cornerCell.text); + var sourceText = info.info.meta.value; + var maxHeight = getWrapTextHeight(getWrapText(sourceText, textStyle, info.info.resizedWidth, ev.spreadsheet), textStyle, ev.spreadsheet, maxLines); + // 获取最大高度的列,排除当前列 + var maxHeightCol = ev.colLeafNodes + .filter(function (n) { return n.colIndex !== info.info.meta.colIndex; }) + .reduce(function (maxHeightNode, currentNode) { + var wrapTextHeight = getWrapTextHeight(getWrapText(currentNode.value, textStyle, currentNode.width, currentNode.spreadsheet), textStyle, currentNode.spreadsheet, maxLines); + return wrapTextHeight > maxHeightNode.height + ? { height: wrapTextHeight, colIndex: currentNode.colIndex } + : maxHeightNode; + }, { height: 0 }); + // 使用最大高度 + maxHeight = Math.max(maxHeight, maxHeightCol.height) + textStyle.fontSize + 10.5; + if (layoutResult) { + if (basicStyle.tableColumnMode === 'adapt') + maxHeight -= textStyle.fontSize - 2; + ev.colLeafNodes.forEach(function (n) { return (n.height = maxHeight); }); + ev.colsHierarchy.height = maxHeight; + } + newChart.store.set('autoCalcHeight', maxHeight); +}; +/** + * 获取换行文本 + * 累加字符串单个字符的宽度,超过单元格宽度时,添加换行 + * @param sourceText + * @param textStyle + * @param cellWidth + * @param spreadsheet + */ +var getWrapText = function (sourceText, textStyle, cellWidth, spreadsheet) { + if (!sourceText && sourceText !== 0) + return ''; + sourceText = sourceText.toString().trim(); + var getTextWidth = function (text) { return spreadsheet.measureTextWidthRoughly(text, textStyle); }; + var resultWrapText = ''; + var restText = ''; + var restTextWidth = 0; + for (var i = 0; i < sourceText.length; i++) { + var char = sourceText[i]; + var charWidth = getTextWidth(char); + restTextWidth += charWidth; + restText += char; + // 中文时,需要单元格宽度减去16个文字宽度,否则会超出单元格宽度 + var cWidth = char.charCodeAt(0) >= 128 ? 12 : 8; + // 添加换行 + if (restTextWidth >= cellWidth - textStyle.fontSize - cWidth) { + // 最后一个字符不添加换行符 + resultWrapText += restText + (i !== sourceText.length - 1 ? '\n' : ''); + restText = ''; + restTextWidth = 0; + } + } + resultWrapText += restText; + return resultWrapText; +}; +/** + * 计算文本行高 + * @param wrapText + * @param textStyle + * @param spreadsheet + * @param maxLines 最大行数 + */ +var getWrapTextHeight = function (wrapText, textStyle, spreadsheet, maxLines) { + // 行内最高 + var maxHeight = 0; + // 获取最高字符的高度 + for (var _i = 0, wrapText_1 = wrapText; _i < wrapText_1.length; _i++) { + var char = wrapText_1[_i]; + var h = textStyle.fontSize / (char.charCodeAt(0) >= 128 ? 5 : 2.5); + maxHeight = Math.max(maxHeight, spreadsheet.measureTextHeight(char, textStyle) + h); + } + // 行数 + var lines = wrapText.split('\n').length; + return Math.min(lines, maxLines) * maxHeight; +}; +// 导出获取汇总行的函数 +function getSummaryRow(data, axis, sumCon) { + if (sumCon === void 0) { sumCon = []; } + var summaryObj = { SUMMARY: true }; + var _loop_3 = function (i) { + var a = axis[i].gisbiName; + var savedAxis = lodash_es_1.find(sumCon, function (s) { return s.field === a; }); + if (savedAxis) { + if (savedAxis.summary == undefined) { + savedAxis.summary = 'sum'; // 默认汇总方式为求和 + } + if (savedAxis.show == undefined) { + savedAxis.show = true; // 默认显示汇总结果 + } + } + else { + savedAxis = { + field: a, + summary: 'sum', + show: true + }; + } + // 如果配置为不显示,则跳过该字段 + if (!savedAxis.show) { + return "continue"; + } + // 根据汇总方式处理数据 + switch (savedAxis.summary) { + case 'sum': + // 计算字段的总和 + summaryObj[a] = util_1.safeDecimalSum(data, a); + break; + case 'avg': + // 计算字段的平均值 + summaryObj[a] = util_1.safeDecimalMean(data, a); + break; + case 'max': + // 计算字段的最大值 + summaryObj[a] = lodash_es_1.maxBy(lodash_es_1.filter(data, function (d) { return parseFloat(d[a]) !== undefined; }), function (d) { return parseFloat(d[a]); } // 提取数值 + )[a]; + break; + case 'min': + // 计算字段的最小值 + summaryObj[a] = lodash_es_1.minBy(lodash_es_1.filter(data, function (d) { return parseFloat(d[a]) !== undefined; }), function (d) { return parseFloat(d[a]); } // 提取数值 + )[a]; + break; + case 'var_pop': + // 计算总体方差(需要至少2个数据点) + if (data.length < 2) { + return "continue"; + } + else { + var mean_1 = util_1.safeDecimalMean(data, a); // 计算平均值 + // 计算每个数据点与平均值的差的平方 + var squaredDeviations = lodash_es_1.map(data, function (d) { + var _a; + var value = new decimal_js_1["default"]((_a = d[a]) !== null && _a !== void 0 ? _a : 0); // 获取字段值,如果不存在则使用0 + var dev = value.minus(mean_1); // 计算差值 + return dev.times(dev); // 计算平方 + }); + // 计算方差(平方差的平均值) + var variance = squaredDeviations.reduce(function (acc, val) { return acc.plus(val); }, new decimal_js_1["default"](0)); + summaryObj[a] = variance.dividedBy(data.length - 1).toNumber(); // 计算总体方差 + } + break; + case 'stddev_pop': + // 计算总体标准差(需要至少2个数据点) + if (data.length < 2) { + return "continue"; + } + else { + var mean_2 = util_1.safeDecimalMean(data, a); // 计算平均值 + // 计算每个数据点与平均值的差的平方 + var squaredDeviations = lodash_es_1.map(data, function (d) { + var _a; + var value = new decimal_js_1["default"]((_a = d[a]) !== null && _a !== void 0 ? _a : 0); // 获取字段值,如果不存在则使用0 + var dev = value.minus(mean_2); // 计算差值 + return dev.times(dev); // 计算平方 + }); + // 计算方差(平方差的平均值) + var variance = squaredDeviations.reduce(function (acc, val) { return acc.plus(val); }, new decimal_js_1["default"](0)); + summaryObj[a] = variance.dividedBy(data.length - 1).sqrt().toNumber(); // 计算总体标准差 + } + break; + } + }; + for (var i = 0; i < axis.length; i++) { + _loop_3(i); + } + // 返回汇总结果对象 + return summaryObj; +} +exports.getSummaryRow = getSummaryRow; +var SummaryCell = /** @class */ (function (_super) { + __extends(SummaryCell, _super); + function SummaryCell() { + return _super !== null && _super.apply(this, arguments) || this; + } + SummaryCell.prototype.getTextStyle = function () { + var textStyle = lodash_es_1.cloneDeep(this.theme.colCell.bolderText); + textStyle.textAlign = this.theme.dataCell.text.textAlign; + return textStyle; + }; + SummaryCell.prototype.getBackgroundColor = function () { + var _a = this.theme.colCell.cell, backgroundColor = _a.backgroundColor, backgroundColorOpacity = _a.backgroundColorOpacity; + return { backgroundColor: backgroundColor, backgroundColorOpacity: backgroundColorOpacity }; + }; + return SummaryCell; +}(CustomDataCell)); +exports.SummaryCell = SummaryCell; +/** + * 配置空数据样式 + * @param newChart + * @param basicStyle + * @param newData + * @param container + */ +exports.configEmptyDataStyle = function (newChart, basicStyle, newData, container) { + /** + * 辅助函数:移除空数据dom + */ + var removeEmptyDom = function () { + var emptyElement = document.getElementById(container + '_empty'); + if (emptyElement) { + emptyElement.parentElement.removeChild(emptyElement); + } + }; + removeEmptyDom(); + if (newData.length) + return; + newChart.on(s2_1.S2Event.LAYOUT_AFTER_HEADER_LAYOUT, function (ev) { + removeEmptyDom(); + if (!newData.length) { + var emptyDom = document.createElement('div'); + var left = Math.min(newChart.options.width, ev.colsHierarchy.width) / 2 - 32; + emptyDom.id = container + '_empty'; + emptyDom.textContent = i18nt('data_set.no_data'); + emptyDom.setAttribute('style', "position: absolute;\n left: " + left + "px;\n top: 50%;"); + var parent = document.getElementById(container); + parent.insertBefore(emptyDom, parent.firstChild); + } + }); +}; +exports.getLeafNodes = function (tree) { + var result = []; + var inorderTraversal = function (node) { + var _a, _b; + if (!((_a = node.children) === null || _a === void 0 ? void 0 : _a.length)) { + // 叶子节点,添加到结果数组 + result.push(node); + return; + } + // 中序遍历 + for (var i = 0; i < ((_b = node.children) === null || _b === void 0 ? void 0 : _b.length); i++) { + inorderTraversal(node.children[i]); + } + }; + // 遍历树中所有节点 + tree.forEach(function (node) { return inorderTraversal(node); }); + return result; +}; +exports.getColumns = function (fields, cols) { + var _a; + var result = []; + for (var i = 0; i < cols.length; i++) { + if (fields.includes(cols[i].key)) { + result.push(cols[i]); + } + if ((_a = cols[i].children) === null || _a === void 0 ? void 0 : _a.length) { + result.push.apply(result, exports.getColumns(fields, cols[i].children)); + } + } + return result; +}; +function drawImage() { + var _this = this; + var img = new Image(); + var _a = this.meta, x = _a.x, y = _a.y, width = _a.width, height = _a.height, fieldValue = _a.fieldValue; + img.src = fieldValue; + img.setAttribute('crossOrigin', 'anonymous'); + img.onload = function () { + !_this.cfg.children && (_this.cfg.children = []); + var imgWidth = img.width, imgHeight = img.height; + var ratio = Math.max(imgWidth / width, imgHeight / height); + // 不铺满,部分留白 + var imgShowWidth = (imgWidth / ratio) * 0.8; + var imgShowHeight = (imgHeight / ratio) * 0.8; + _this.textShape = _this.addShape('image', { + attrs: { + x: x + (imgShowWidth < width ? (width - imgShowWidth) / 2 : 0), + y: y + (imgShowHeight < height ? (height - imgShowHeight) / 2 : 0), + width: imgShowWidth, + height: imgShowHeight, + img: img + } + }); + }; +} +exports.drawImage = drawImage; diff --git a/frontend/src/data-visualization/chart/components/js/panel/types/impl/g2plot.ts b/frontend/src/data-visualization/chart/components/js/panel/types/impl/g2plot.ts index c8269b5..dd32468 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/types/impl/g2plot.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/types/impl/g2plot.ts @@ -170,7 +170,7 @@ export abstract class G2PlotChartView< public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] { return setupSeriesColor(chart, data) } - + // eslint-disable-next-line public setupSubSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] { return undefined } @@ -191,8 +191,8 @@ export abstract class G2PlotChartView< return addConditionsStyleColorToData(chart, data) } - protected configEmptyDataStyle(newChart, newData: any[], container: string) { - configEmptyDataStyle(newChart, newData, container) + protected configEmptyDataStyle(newData, container, newChart?, content?) { + configEmptyDataStyle(newData, container, newChart, content) } /** diff --git a/frontend/src/data-visualization/chart/components/js/panel/types/impl/l7.ts b/frontend/src/data-visualization/chart/components/js/panel/types/impl/l7.ts index 24bd6aa..093ffd1 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/types/impl/l7.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/types/impl/l7.ts @@ -107,8 +107,8 @@ export abstract class L7ChartView< return options } - protected configZoomButton(chart: Chart, plot: S) { - configL7Zoom(chart, plot) + protected configZoomButton(chart: Chart, plot: S, mapKey?: any) { + configL7Zoom(chart, plot, mapKey) } protected configLabel(chart: Chart, options: O): O { diff --git a/frontend/src/data-visualization/chart/components/js/panel/types/impl/s2.ts b/frontend/src/data-visualization/chart/components/js/panel/types/impl/s2.ts index 3bcc669..2ec21e4 100644 --- a/frontend/src/data-visualization/chart/components/js/panel/types/impl/s2.ts +++ b/frontend/src/data-visualization/chart/components/js/panel/types/impl/s2.ts @@ -136,18 +136,18 @@ export abstract class S2ChartView

    extends AntVAbstractCha if (duration > 300) { return } + const canvasPosition = canvas.getBoundingClientRect() + const touchPosition = [e.changedTouches[0].pageX, e.changedTouches[0].pageY] + const relativePosition = [ + touchPosition[0] - canvasPosition.x, + touchPosition[1] - canvasPosition.y + ] + const shape = s2Instance.container.getShape(relativePosition[0], relativePosition[1]) + // 图片单元格,表头排序图标点击放大图片 + if (shape.cfg?.type === 'image') { + return + } const callback = () => { - const canvasPosition = canvas.getBoundingClientRect() - const touchPosition = [e.changedTouches[0].pageX, e.changedTouches[0].pageY] - const relativePosition = [ - touchPosition[0] - canvasPosition.x, - touchPosition[1] - canvasPosition.y - ] - const shape = s2Instance.container.getShape(relativePosition[0], relativePosition[1]) - // 图片单元格点击放大图片 - if (shape.cfg?.parent.constructor.name === 'ImageCell') { - return - } e.preventDefault() e.stopPropagation() if (shape) {