From 12b33f2528935e444dd6e8e1b57822c406d4ff70 Mon Sep 17 00:00:00 2001 From: wisonic-s Date: Wed, 20 Mar 2024 20:23:05 +0800 Subject: [PATCH] =?UTF-8?q?faet(=E8=A7=86=E5=9B=BE):=20AntV=20=E6=8A=98?= =?UTF-8?q?=E7=BA=BF=E5=9B=BE=E6=94=AF=E6=8C=81=E8=B6=8B=E5=8A=BF=E7=BA=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/frontend/src/lang/en.js | 11 +- core/frontend/src/lang/tw.js | 11 +- core/frontend/src/lang/zh.js | 11 +- .../src/views/chart/chart/bar/bar_antv.js | 34 +- .../views/chart/chart/common/common_antv.js | 89 +++++- .../views/chart/chart/funnel/funnel_antv.js | 9 +- .../src/views/chart/chart/gauge/gauge_antv.js | 10 +- .../src/views/chart/chart/line/line_antv.js | 23 +- .../src/views/chart/chart/liquid/liquid.js | 9 +- .../src/views/chart/chart/mix/mix_antv.js | 10 +- .../src/views/chart/chart/pie/pie_antv.js | 18 +- .../src/views/chart/chart/radar/radar_antv.js | 8 +- .../views/chart/chart/scatter/scatter_antv.js | 8 +- .../views/chart/chart/treemap/treemap_antv.js | 9 +- core/frontend/src/views/chart/chart/util.js | 14 +- .../views/chart/chart/waterfall/waterfall.js | 9 +- .../views/chart/chart/wordCloud/word_cloud.js | 9 +- .../chart/components/ChartComponentG2.vue | 66 ++-- .../chart/components/senior/TrendLine.vue | 217 +++++++++++++ .../senior/dialog/TrendLineEdit.vue | 297 ++++++++++++++++++ .../src/views/chart/view/ChartEdit.vue | 26 +- 21 files changed, 735 insertions(+), 163 deletions(-) create mode 100644 core/frontend/src/views/chart/components/senior/TrendLine.vue create mode 100644 core/frontend/src/views/chart/components/senior/dialog/TrendLineEdit.vue diff --git a/core/frontend/src/lang/en.js b/core/frontend/src/lang/en.js index 03c9faf2a4..fee6c30ffa 100644 --- a/core/frontend/src/lang/en.js +++ b/core/frontend/src/lang/en.js @@ -1643,7 +1643,16 @@ export default { word_size_range: 'Word Size Range', word_spacing: 'Word Spacing', axis_multi_select_tip: 'Hold down the Ctrl/Cmd or Shift key and click to select more than one', - needs_to_be_integer: 'Needs to be an integer' + needs_to_be_integer: 'Needs to be an integer', + regression_poly: 'Polynomial', + regression_linear: 'Linear', + regression_exp: 'Exponential', + regression_log: 'Logarithmic', + regression_quad: 'Quadratic', + regression_pow: 'Power law', + regression_loess: 'LOESS', + regression_algo: 'Algorithm', + trend_line: 'Trend Line' }, dataset: { scope_edit: 'Effective only when editing', diff --git a/core/frontend/src/lang/tw.js b/core/frontend/src/lang/tw.js index ea5677ab03..897675a705 100644 --- a/core/frontend/src/lang/tw.js +++ b/core/frontend/src/lang/tw.js @@ -1635,7 +1635,16 @@ export default { word_size_range: '字號區間', word_spacing: '文字間隔', axis_multi_select_tip: '按住 Ctrl/Cmd 鍵或者 Shift 鍵再點擊可多選', - needs_to_be_integer: '需要為整數' + needs_to_be_integer: '需要為整數', + regression_poly: '多項式', + regression_linear: '線性', + regression_exp: '指數', + regression_log: '對數', + regression_quad: '二次項', + regression_pow: '冪函數', + regression_loess: '局部加權', + regression_algo: '算法', + trend_line: '趨勢線' }, dataset: { scope_edit: '僅編輯時生效', diff --git a/core/frontend/src/lang/zh.js b/core/frontend/src/lang/zh.js index f4cc9960ea..949c1b4d07 100644 --- a/core/frontend/src/lang/zh.js +++ b/core/frontend/src/lang/zh.js @@ -1635,7 +1635,16 @@ export default { word_size_range: '字号区间', word_spacing: '文字间隔', axis_multi_select_tip: '按住 Ctrl/Cmd 键或者 Shift 键再点击可多选', - needs_to_be_integer: '需要为整数' + needs_to_be_integer: '需要为整数', + regression_poly: '多项式', + regression_linear: '线性', + regression_exp: '指数', + regression_log: '对数', + regression_quad: '二次项', + regression_pow: '幂函数', + regression_loess: '局部加权', + regression_algo: '算法', + trend_line: '趋势线' }, dataset: { scope_edit: '仅编辑时生效', diff --git a/core/frontend/src/views/chart/chart/bar/bar_antv.js b/core/frontend/src/views/chart/chart/bar/bar_antv.js index aa0f41b901..c546873080 100644 --- a/core/frontend/src/views/chart/chart/bar/bar_antv.js +++ b/core/frontend/src/views/chart/chart/bar/bar_antv.js @@ -16,7 +16,7 @@ import { import { antVCustomColor, getColors, handleEmptyDataStrategy, hexColorToRGBA } from '@/views/chart/chart/util' import { cloneDeep, find } from 'lodash-es' -export function baseBarOptionAntV(plot, container, chart, action, isGroup, isStack) { +export function baseBarOptionAntV(container, chart, action, isGroup, isStack) { // theme const theme = getTheme(chart) // attr @@ -132,19 +132,15 @@ export function baseBarOptionAntV(plot, container, chart, action, isGroup, isSta } // 开始渲染 - if (plot) { - plot.destroy() - } - plot = new Column(container, options) + const plot = new Column(container, options) - plot.off('interval:click') plot.on('interval:click', action) // 处理 tooltip 被其他视图遮挡 configPlotTooltipEvent(chart, plot) return plot } -export function hBaseBarOptionAntV(plot, container, chart, action, isGroup, isStack) { +export function hBaseBarOptionAntV(container, chart, action, isGroup, isStack) { // theme const theme = getTheme(chart) // attr @@ -252,20 +248,15 @@ export function hBaseBarOptionAntV(plot, container, chart, action, isGroup, isSt handleEmptyDataStrategy(emptyDataStrategy, chart, data, options) } - // 开始渲染 - if (plot) { - plot.destroy() - } - plot = new Bar(container, options) + const plot = new Bar(container, options) - plot.off('interval:click') plot.on('interval:click', action) // 处理 tooltip 被其他视图遮挡 configPlotTooltipEvent(chart, plot) return plot } -export function timeRangeBarOptionAntV(plot, container, chart, action) { +export function timeRangeBarOptionAntV(container, chart, action) { const ifAggregate = !!chart.aggregate // theme @@ -446,11 +437,7 @@ export function timeRangeBarOptionAntV(plot, container, chart, action) { handleEmptyDataStrategy(emptyDataStrategy, chart, data, options) } - // 开始渲染 - if (plot) { - plot.destroy() - } - plot = new Bar(container, options) + const plot = new Bar(container, options) plot.off('interval:click') plot.on('interval:click', action) @@ -459,7 +446,7 @@ export function timeRangeBarOptionAntV(plot, container, chart, action) { return plot } -export function baseBidirectionalBarOptionAntV(plot, container, chart, action, isGroup, isStack) { +export function baseBidirectionalBarOptionAntV(container, chart, action, isGroup, isStack) { // theme const theme = getTheme(chart) // attr @@ -542,13 +529,8 @@ export function baseBidirectionalBarOptionAntV(plot, container, chart, action, i if (meta) { options.meta = meta } - // 开始渲染 - if (plot) { - plot.destroy() - } - plot = new BidirectionalBar(container, options) + const plot = new BidirectionalBar(container, options) - plot.off('interval:click') plot.on('interval:click', action) // 处理 tooltip 被其他视图遮挡 configPlotTooltipEvent(chart, plot) diff --git a/core/frontend/src/views/chart/chart/common/common_antv.js b/core/frontend/src/views/chart/chart/common/common_antv.js index 010a5a8f1a..619097caff 100644 --- a/core/frontend/src/views/chart/chart/common/common_antv.js +++ b/core/frontend/src/views/chart/chart/common/common_antv.js @@ -3,7 +3,15 @@ import { formatterItem, valueFormatter } from '@/views/chart/chart/formatter' import { DEFAULT_XAXIS_STYLE, DEFAULT_YAXIS_EXT_STYLE, DEFAULT_YAXIS_STYLE } from '@/views/chart/chart/chart' import { equalsAny, includesAny } from '@/utils/StringUtils' import i18n from '@/lang' - +import { + regressionExp, + regressionPoly, + regressionLinear, + regressionLoess, + regressionLog, + regressionPow, + regressionQuad +} from 'd3-regression/dist/d3-regression.esm' export function getPadding(chart) { if (chart.drill) { return [0, 10, 26, 10] @@ -1258,3 +1266,82 @@ export const configTopN = (data, chart) => { }, initOtherItem) data.push(initOtherItem) } +const REGRESSION_ALGO_MAP = { + poly: regressionPoly, + linear: regressionLinear, + exp: regressionExp, + log: regressionLog, + quad: regressionQuad, + pow: regressionPow, + loess: regressionLoess +} +export function configPlotTrendLine(chart, plot) { + const senior = JSON.parse(chart.senior) + if (!senior?.trendLine?.length || !chart.data?.data?.length) { + return + } + const originData = chart.data.data + const originFieldDataMap = {} + originData.forEach(item => { + if (item.quotaList?.length) { + const quota = item.quotaList[0] + if (!originFieldDataMap[quota.id]) { + originFieldDataMap[quota.id] = [] + } + originFieldDataMap[quota.id].push(item.value) + } + }) + const trendResultData = {} + const totalData = [] + const trendLineMap = senior.trendLine.reduce((p, n) => { + const fieldData = originFieldDataMap[n.fieldId] + if (!fieldData?.length) { + return p + } + const regAlgo = REGRESSION_ALGO_MAP[n.algoType]() + .x((_, i) => i) + .y(d => d) + const result = regAlgo(fieldData) + trendResultData[n.fieldId] = result + result.forEach(item => { + totalData.push({ index: item[0], value: item[1], color: n.color, field: n.fieldId }) + }) + p[n.fieldId] = n + return p + }, {}) + if (!totalData.length) { + return + } + const regLine = plot.chart.createView() + plot.once('afterrender', () => { + for (const fieldId in trendResultData) { + const trendLine = trendLineMap[fieldId] + const trendData = trendResultData[fieldId] + regLine.annotation().text({ + content: trendLine.name, + position: [0, trendData[0][1]], + style: { + textBaseline: 'bottom', + fill: trendLine.color, + fontSize: trendLine.fontSize ?? 20, + fontWeight: 300 + }, + offsetY: 10 + }) + } + regLine.axis(false); + regLine.data(totalData); + regLine.line() + .position('index*value') + .color('color', color => color) + .style('field',field => { + const trend = trendLineMap[field] + return { + stroke: trend?.color ?? 'grey', + lineDash: trend?.lineType ? getLineDash(trend.lineType) : [0, 0] + } + }) + .tooltip(false) + regLine.render() + }) +} diff --git a/core/frontend/src/views/chart/chart/funnel/funnel_antv.js b/core/frontend/src/views/chart/chart/funnel/funnel_antv.js index d2632978e8..3adb30d4aa 100644 --- a/core/frontend/src/views/chart/chart/funnel/funnel_antv.js +++ b/core/frontend/src/views/chart/chart/funnel/funnel_antv.js @@ -9,7 +9,7 @@ import { import { Funnel } from '@antv/g2plot' import { antVCustomColor } from '@/views/chart/chart/util' -export function baseFunnelOptionAntV(plot, container, chart, action) { +export function baseFunnelOptionAntV(container, chart, action) { // theme const theme = getTheme(chart) // attr @@ -53,13 +53,8 @@ export function baseFunnelOptionAntV(plot, container, chart, action) { // custom color options.color = antVCustomColor(chart) - // 开始渲染 - if (plot) { - plot.destroy() - } - plot = new Funnel(container, options) + const plot = new Funnel(container, options) - plot.off('interval:click') plot.on('interval:click', action) // 处理 tooltip 被其他视图遮挡 configPlotTooltipEvent(chart, plot) diff --git a/core/frontend/src/views/chart/chart/gauge/gauge_antv.js b/core/frontend/src/views/chart/chart/gauge/gauge_antv.js index a41bff3807..802ccbcfd1 100644 --- a/core/frontend/src/views/chart/chart/gauge/gauge_antv.js +++ b/core/frontend/src/views/chart/chart/gauge/gauge_antv.js @@ -6,7 +6,7 @@ import { valueFormatter } from '@/views/chart/chart/formatter' let labelFormatter = null -export function baseGaugeOptionAntV(plot, container, chart, action, scale = 1) { +export function baseGaugeOptionAntV(container, chart, action, scale = 1) { let min, max, labelContent, startAngel, endAngel // theme const theme = getTheme(chart) @@ -170,11 +170,5 @@ export function baseGaugeOptionAntV(plot, container, chart, action, scale = 1) { } } - // 开始渲染 - if (plot) { - plot.destroy() - } - plot = new Gauge(container, options) - - return plot + return new Gauge(container, options) } diff --git a/core/frontend/src/views/chart/chart/line/line_antv.js b/core/frontend/src/views/chart/chart/line/line_antv.js index df3c81549e..596a620053 100644 --- a/core/frontend/src/views/chart/chart/line/line_antv.js +++ b/core/frontend/src/views/chart/chart/line/line_antv.js @@ -10,12 +10,13 @@ import { getSlider, getAnalyse, setGradientColor, - configPlotTooltipEvent + configPlotTooltipEvent, + configPlotTrendLine } from '@/views/chart/chart/common/common_antv' import { antVCustomColor, handleEmptyDataStrategy } from '@/views/chart/chart/util' import _ from 'lodash' -export function baseLineOptionAntV(plot, container, chart, action) { +export function baseLineOptionAntV(container, chart, action) { // theme const theme = getTheme(chart) // attr @@ -103,20 +104,17 @@ export function baseLineOptionAntV(plot, container, chart, action) { } handleEmptyDataStrategy(emptyDataStrategy, chart, data, options) } - // 开始渲染 - if (plot) { - plot.destroy() - } - plot = new Line(container, options) + const plot = new Line(container, options) - plot.off('point:click') plot.on('point:click', action) + // 趋势线 + configPlotTrendLine(chart, plot) // 处理 tooltip 被其他视图遮挡 configPlotTooltipEvent(chart, plot) return plot } -export function baseAreaOptionAntV(plot, container, chart, action, isStack) { +export function baseAreaOptionAntV(container, chart, action, isStack) { // theme const theme = getTheme(chart) // attr @@ -214,13 +212,8 @@ export function baseAreaOptionAntV(plot, container, chart, action, isStack) { handleEmptyDataStrategy(emptyDataStrategy, chart, data, options) } - // 开始渲染 - if (plot) { - plot.destroy() - } - plot = new Area(container, options) + const plot = new Area(container, options) - plot.off('point:click') plot.on('point:click', action) // 处理 tooltip 被其他视图遮挡 configPlotTooltipEvent(chart, plot) diff --git a/core/frontend/src/views/chart/chart/liquid/liquid.js b/core/frontend/src/views/chart/chart/liquid/liquid.js index ff0c996817..c5f8fcd3a5 100644 --- a/core/frontend/src/views/chart/chart/liquid/liquid.js +++ b/core/frontend/src/views/chart/chart/liquid/liquid.js @@ -5,7 +5,7 @@ import { valueFormatter } from '@/views/chart/chart/formatter' let labelFormatter = null -export function baseLiquid(plot, container, chart) { +export function baseLiquid(container, chart) { let value = 0 const colors = [] let max, radius, bgColor, shape, labelContent, liquidStyle, originVal = 0 @@ -80,11 +80,7 @@ export function baseLiquid(plot, container, chart) { bgColor = hexColorToRGBA(customStyle.background.color, customStyle.background.alpha) } } - // 开始渲染 - if (plot) { - plot.destroy() - } - plot = new Liquid(container, { + return new Liquid(container, { theme: { styleSheet: { brandColor: colors[0], @@ -101,5 +97,4 @@ export function baseLiquid(plot, container, chart) { }, liquidStyle }) - return plot } diff --git a/core/frontend/src/views/chart/chart/mix/mix_antv.js b/core/frontend/src/views/chart/chart/mix/mix_antv.js index a41c813946..ef63aafb21 100644 --- a/core/frontend/src/views/chart/chart/mix/mix_antv.js +++ b/core/frontend/src/views/chart/chart/mix/mix_antv.js @@ -12,7 +12,7 @@ import { import { Mix } from '@antv/g2plot' import { hexColorToRGBA } from '@/views/chart/chart/util' -export function baseMixOptionAntV(plot, container, chart, action) { +export function baseMixOptionAntV(container, chart, action) { // theme const theme = getTheme(chart) // attr @@ -98,15 +98,9 @@ export function baseMixOptionAntV(plot, container, chart, action) { tooltip: { shared: true } } - // 开始渲染 - if (plot) { - plot.destroy() - } - plot = new Mix(container, options) + const plot = new Mix(container, options) - plot.off('point:click') plot.on('point:click', action) - plot.off('interval:click') plot.on('interval:click', action) // 处理 tooltip 被其他视图遮挡 configPlotTooltipEvent(chart, plot) diff --git a/core/frontend/src/views/chart/chart/pie/pie_antv.js b/core/frontend/src/views/chart/chart/pie/pie_antv.js index 339c007ac4..d43516a4f2 100644 --- a/core/frontend/src/views/chart/chart/pie/pie_antv.js +++ b/core/frontend/src/views/chart/chart/pie/pie_antv.js @@ -11,7 +11,7 @@ import { Pie, Rose } from '@antv/g2plot' import { antVCustomColor } from '@/views/chart/chart/util' import { configTopN } from '@/views/chart/chart/common/common_antv' -export function basePieOptionAntV(plot, container, chart, action) { +export function basePieOptionAntV(container, chart, action) { // theme const theme = getTheme(chart) // attr @@ -85,20 +85,15 @@ export function basePieOptionAntV(plot, container, chart, action) { options.color = antVCustomColor(chart) // topN configTopN(data, chart) - // 开始渲染 - if (plot) { - plot.destroy() - } - plot = new Pie(container, options) + const plot = new Pie(container, options) - plot.off('interval:click') plot.on('interval:click', action) // 处理 tooltip 被其他视图遮挡 configPlotTooltipEvent(chart, plot) return plot } -export function basePieRoseOptionAntV(plot, container, chart, action) { +export function basePieRoseOptionAntV(container, chart, action) { // theme const theme = getTheme(chart) // attr @@ -163,13 +158,8 @@ export function basePieRoseOptionAntV(plot, container, chart, action) { // custom color options.color = antVCustomColor(chart) - // 开始渲染 - if (plot) { - plot.destroy() - } - plot = new Rose(container, options) + const plot = new Rose(container, options) - plot.off('interval:click') plot.on('interval:click', action) // 处理 tooltip 被其他视图遮挡 configPlotTooltipEvent(chart, plot) diff --git a/core/frontend/src/views/chart/chart/radar/radar_antv.js b/core/frontend/src/views/chart/chart/radar/radar_antv.js index 3a01685023..dc7730f3b8 100644 --- a/core/frontend/src/views/chart/chart/radar/radar_antv.js +++ b/core/frontend/src/views/chart/chart/radar/radar_antv.js @@ -10,7 +10,7 @@ import { Radar } from '@antv/g2plot' import { antVCustomColor } from '@/views/chart/chart/util' import { minBy, maxBy } from 'lodash' -export function baseRadarOptionAntV(plot, container, chart, action) { +export function baseRadarOptionAntV(container, chart, action) { // theme const theme = getTheme(chart) // attr @@ -145,11 +145,7 @@ export function baseRadarOptionAntV(plot, container, chart, action) { // custom color options.color = antVCustomColor(chart) - // 开始渲染 - if (plot) { - plot.destroy() - } - plot = new Radar(container, options) + const plot = new Radar(container, options) plot.off('point:click') plot.on('point:click', action) diff --git a/core/frontend/src/views/chart/chart/scatter/scatter_antv.js b/core/frontend/src/views/chart/chart/scatter/scatter_antv.js index 57f8611cc4..4b6beee365 100644 --- a/core/frontend/src/views/chart/chart/scatter/scatter_antv.js +++ b/core/frontend/src/views/chart/chart/scatter/scatter_antv.js @@ -16,7 +16,7 @@ import { import { Scatter } from '@antv/g2plot' import { antVCustomColor } from '@/views/chart/chart/util' -export function baseScatterOptionAntV(plot, container, chart, action) { +export function baseScatterOptionAntV(container, chart, action) { // theme const theme = getTheme(chart) // attr @@ -87,11 +87,7 @@ export function baseScatterOptionAntV(plot, container, chart, action) { // custom color options.color = antVCustomColor(chart) - // 开始渲染 - if (plot) { - plot.destroy() - } - plot = new Scatter(container, options) + const plot = new Scatter(container, options) plot.off('point:click') plot.on('point:click', action) diff --git a/core/frontend/src/views/chart/chart/treemap/treemap_antv.js b/core/frontend/src/views/chart/chart/treemap/treemap_antv.js index 91def99b53..bcd7be3849 100644 --- a/core/frontend/src/views/chart/chart/treemap/treemap_antv.js +++ b/core/frontend/src/views/chart/chart/treemap/treemap_antv.js @@ -8,7 +8,7 @@ import { } from '@/views/chart/chart/common/common_antv' import { Treemap } from '@antv/g2plot' -export function baseTreemapOptionAntV(plot, container, chart, action) { +export function baseTreemapOptionAntV(container, chart, action) { // theme const theme = getTheme(chart) // attr @@ -50,13 +50,8 @@ export function baseTreemapOptionAntV(plot, container, chart, action) { } ] } - // 开始渲染 - if (plot) { - plot.destroy() - } - plot = new Treemap(container, options) + const plot = new Treemap(container, options) - plot.off('polygon:click') plot.on('polygon:click', action) // 处理 tooltip 被其他视图遮挡 configPlotTooltipEvent(chart, plot) diff --git a/core/frontend/src/views/chart/chart/util.js b/core/frontend/src/views/chart/chart/util.js index 2679964e18..eaf2510e61 100644 --- a/core/frontend/src/views/chart/chart/util.js +++ b/core/frontend/src/views/chart/chart/util.js @@ -3776,6 +3776,7 @@ export function handleEmptyDataStrategy(strategy, chart, data, options) { function handleBreakLineMultiDimension(chart, data) { const dimensionInfoMap = new Map() const subDimensionSet = new Set() + const catQuotaMap = {} for (let i = 0; i < data.length; i++) { const item = data[i] const dimensionInfo = dimensionInfoMap.get(item.field) @@ -3785,6 +3786,9 @@ function handleBreakLineMultiDimension(chart, data) { dimensionInfoMap.set(item.field, { set: new Set([item.category]), index: i }) } subDimensionSet.add(item.category) + if (!catQuotaMap[item.category]) { + catQuotaMap[item.category] = item.quotaList + } } // Map 是按照插入顺序排序的,所以插入索引往后推 let insertCount = 0 @@ -3796,7 +3800,8 @@ function handleBreakLineMultiDimension(chart, data) { data.splice(dimensionInfo.index + insertCount + subInsertIndex, 0, { field, value: null, - category: dimension + category: dimension, + quotaList: catQuotaMap[dimension] }) } subInsertIndex++ @@ -3809,6 +3814,7 @@ function handleBreakLineMultiDimension(chart, data) { function handleSetZeroMultiDimension(chart, data) { const dimensionInfoMap = new Map() const subDimensionSet = new Set() + const catQuotaMap = {} for (let i = 0; i < data.length; i++) { const item = data[i] if (item.value === null) { @@ -3821,6 +3827,9 @@ function handleSetZeroMultiDimension(chart, data) { dimensionInfoMap.set(item.field, { set: new Set([item.category]), index: i }) } subDimensionSet.add(item.category) + if (!catQuotaMap[item.category]) { + catQuotaMap[item.category] = item.quotaList + } } let insertCount = 0 dimensionInfoMap.forEach((dimensionInfo, field) => { @@ -3831,7 +3840,8 @@ function handleSetZeroMultiDimension(chart, data) { data.splice(dimensionInfo.index + insertCount + subInsertIndex, 0, { field, value: 0, - category: dimension + category: dimension, + quotaList: catQuotaMap[dimension] }) } subInsertIndex++ diff --git a/core/frontend/src/views/chart/chart/waterfall/waterfall.js b/core/frontend/src/views/chart/chart/waterfall/waterfall.js index d5e9886423..03ede5d92c 100644 --- a/core/frontend/src/views/chart/chart/waterfall/waterfall.js +++ b/core/frontend/src/views/chart/chart/waterfall/waterfall.js @@ -11,7 +11,7 @@ import { import { Waterfall } from '@antv/g2plot' import { formatterItem, valueFormatter } from '@/views/chart/chart/formatter' -export function baseWaterfallOptionAntV(plot, container, chart, action) { +export function baseWaterfallOptionAntV(container, chart, action) { // theme const theme = getTheme(chart) // attr @@ -101,13 +101,8 @@ export function baseWaterfallOptionAntV(plot, container, chart, action) { } } - // 开始渲染 - if (plot) { - plot.destroy() - } - plot = new Waterfall(container, options) + const plot = new Waterfall(container, options) - plot.off('interval:click') plot.on('interval:click', action) // 处理 tooltip 被其他视图遮挡 configPlotTooltipEvent(chart, plot) diff --git a/core/frontend/src/views/chart/chart/wordCloud/word_cloud.js b/core/frontend/src/views/chart/chart/wordCloud/word_cloud.js index 0095f2baf7..3fadf6f5b4 100644 --- a/core/frontend/src/views/chart/chart/wordCloud/word_cloud.js +++ b/core/frontend/src/views/chart/chart/wordCloud/word_cloud.js @@ -6,7 +6,7 @@ import { } from '@/views/chart/chart/common/common_antv' import { WordCloud } from '@antv/g2plot' -export function baseWordCloudOptionAntV(plot, container, chart, action) { +export function baseWordCloudOptionAntV(container, chart, action) { // theme const theme = getTheme(chart) // attr @@ -42,12 +42,7 @@ export function baseWordCloudOptionAntV(plot, container, chart, action) { ] } - // 开始渲染 - if (plot) { - plot.destroy() - } - plot = new WordCloud(container, options) - plot.off('point:click') + const plot = new WordCloud(container, options) plot.on('point:click', action) // 处理 tooltip 被其他视图遮挡 configPlotTooltipEvent(chart, plot) diff --git a/core/frontend/src/views/chart/components/ChartComponentG2.vue b/core/frontend/src/views/chart/components/ChartComponentG2.vue index 3d4d5a2658..da2fb27a7f 100644 --- a/core/frontend/src/views/chart/components/ChartComponentG2.vue +++ b/core/frontend/src/views/chart/components/ChartComponentG2.vue @@ -119,7 +119,6 @@ export default { background: '' }, title_show: true, - antVRenderStatus: false, linkageActiveParam: null, linkageActiveHistory: false, remarkCfg: { @@ -160,7 +159,7 @@ export default { } }, beforeDestroy() { - if (this.myChart.container) { + if (this.myChart?.container) { if (typeof this.myChart.container.getAttribute === 'function') { clear(this.myChart.container) } @@ -191,7 +190,7 @@ export default { methods: { reDrawView() { this.linkageActiveHistory = false - this.myChart.render() + this.myChart?.render() }, linkageActivePre() { if (this.linkageActiveHistory) { @@ -238,7 +237,6 @@ export default { }, async drawView() { const chart = JSON.parse(JSON.stringify(this.chart)) - this.antVRenderStatus = true if (!chart.data || (!chart.data.data && !chart.data.series)) { chart.data = { data: [{}], @@ -249,57 +247,53 @@ export default { ] } } + this.myChart?.destroy() if (chart.type === 'bar') { - this.myChart = baseBarOptionAntV(this.myChart, this.chartId, chart, this.antVAction, true, false) + this.myChart = baseBarOptionAntV(this.chartId, chart, this.antVAction, true, false) } else if (chart.type === 'bar-group') { - this.myChart = baseBarOptionAntV(this.myChart, this.chartId, chart, this.antVAction, true, false) + this.myChart = baseBarOptionAntV(this.chartId, chart, this.antVAction, true, false) } else if (equalsAny(chart.type, 'bar-stack', 'percentage-bar-stack')) { - this.myChart = baseBarOptionAntV(this.myChart, this.chartId, chart, this.antVAction, false, true) + this.myChart = baseBarOptionAntV(this.chartId, chart, this.antVAction, false, true) } else if (chart.type === 'bar-group-stack') { - this.myChart = baseBarOptionAntV(this.myChart, this.chartId, chart, this.antVAction, true, true) + this.myChart = baseBarOptionAntV(this.chartId, chart, this.antVAction, true, true) } else if (chart.type === 'bar-horizontal') { - this.myChart = hBaseBarOptionAntV(this.myChart, this.chartId, chart, this.antVAction, true, false) + this.myChart = hBaseBarOptionAntV(this.chartId, chart, this.antVAction, true, false) } else if (equalsAny(chart.type, 'bar-stack-horizontal', 'percentage-bar-stack-horizontal')) { - this.myChart = hBaseBarOptionAntV(this.myChart, this.chartId, chart, this.antVAction, false, true) + this.myChart = hBaseBarOptionAntV(this.chartId, chart, this.antVAction, false, true) } else if (equalsAny(chart.type, 'bar-time-range')) { - this.myChart = timeRangeBarOptionAntV(this.myChart, this.chartId, chart, this.antVAction) + this.myChart = timeRangeBarOptionAntV(this.chartId, chart, this.antVAction) } else if (chart.type === 'line') { - this.myChart = baseLineOptionAntV(this.myChart, this.chartId, chart, this.antVAction) + this.myChart = baseLineOptionAntV(this.chartId, chart, this.antVAction) } else if (chart.type === 'area') { - this.myChart = baseAreaOptionAntV(this.myChart, this.chartId, chart, this.antVAction, false) + this.myChart = baseAreaOptionAntV(this.chartId, chart, this.antVAction, false) } else if (chart.type === 'line-stack') { - this.myChart = baseAreaOptionAntV(this.myChart, this.chartId, chart, this.antVAction, true) + this.myChart = baseAreaOptionAntV(this.chartId, chart, this.antVAction, true) } else if (chart.type === 'scatter') { - this.myChart = baseScatterOptionAntV(this.myChart, this.chartId, chart, this.antVAction) + this.myChart = baseScatterOptionAntV(this.chartId, chart, this.antVAction) } else if (chart.type === 'radar') { - this.myChart = baseRadarOptionAntV(this.myChart, this.chartId, chart, this.antVAction) + this.myChart = baseRadarOptionAntV(this.chartId, chart, this.antVAction) } else if (chart.type === 'gauge') { - this.myChart = baseGaugeOptionAntV(this.myChart, this.chartId, chart, this.antVAction, this.scale) + this.myChart = baseGaugeOptionAntV(this.chartId, chart, this.antVAction, this.scale) } else if (chart.type === 'pie' || chart.type === 'pie-donut') { - this.myChart = basePieOptionAntV(this.myChart, this.chartId, chart, this.antVAction) + this.myChart = basePieOptionAntV(this.chartId, chart, this.antVAction) } else if (chart.type === 'pie-rose' || chart.type === 'pie-donut-rose') { - this.myChart = basePieRoseOptionAntV(this.myChart, this.chartId, chart, this.antVAction) + this.myChart = basePieRoseOptionAntV(this.chartId, chart, this.antVAction) } else if (chart.type === 'funnel') { - this.myChart = baseFunnelOptionAntV(this.myChart, this.chartId, chart, this.antVAction) + this.myChart = baseFunnelOptionAntV(this.chartId, chart, this.antVAction) } else if (chart.type === 'treemap') { - this.myChart = baseTreemapOptionAntV(this.myChart, this.chartId, chart, this.antVAction) + this.myChart = baseTreemapOptionAntV(this.chartId, chart, this.antVAction) } else if (chart.type === 'liquid') { - this.myChart = baseLiquid(this.myChart, this.chartId, chart) + this.myChart = baseLiquid(this.chartId, chart) } else if (chart.type === 'waterfall') { - this.myChart = baseWaterfallOptionAntV(this.myChart, this.chartId, chart, this.antVAction) + this.myChart = baseWaterfallOptionAntV(this.chartId, chart, this.antVAction) } else if (chart.type === 'word-cloud') { - this.myChart = baseWordCloudOptionAntV(this.myChart, this.chartId, chart, this.antVAction) + this.myChart = baseWordCloudOptionAntV(this.chartId, chart, this.antVAction) } else if (chart.type === 'chart-mix') { - this.myChart = baseMixOptionAntV(this.myChart, this.chartId, chart, this.antVAction) + this.myChart = baseMixOptionAntV(this.chartId, chart, this.antVAction) } else if (chart.type === 'flow-map') { - this.myChart = await baseFlowMapOption(this.myChart, this.chartId, chart, this.antVAction) + this.myChart = await baseFlowMapOption(this.chartId, chart, this.antVAction) } else if (chart.type === 'bidirectional-bar') { - this.myChart = baseBidirectionalBarOptionAntV(this.myChart, this.chartId, chart, this.antVAction) - } else { - if (this.myChart) { - this.antVRenderStatus = false - this.myChart.destroy() - } + this.myChart = baseBidirectionalBarOptionAntV(this.chartId, chart, this.antVAction) } if (this.myChart && !equalsAny(chart.type, 'liquid', 'flow-map') && this.searchCount > 0) { @@ -324,11 +318,9 @@ export default { } } - if (this.antVRenderStatus) { - this.myChart.render() - if (this.linkageActiveHistory) { - this.linkageActive() - } + this.myChart?.render() + if (this.linkageActiveHistory) { + this.linkageActive() } this.setBackGroundBorder() }, diff --git a/core/frontend/src/views/chart/components/senior/TrendLine.vue b/core/frontend/src/views/chart/components/senior/TrendLine.vue new file mode 100644 index 0000000000..e42bffa7d8 --- /dev/null +++ b/core/frontend/src/views/chart/components/senior/TrendLine.vue @@ -0,0 +1,217 @@ + + + + + diff --git a/core/frontend/src/views/chart/components/senior/dialog/TrendLineEdit.vue b/core/frontend/src/views/chart/components/senior/dialog/TrendLineEdit.vue new file mode 100644 index 0000000000..93a47b7008 --- /dev/null +++ b/core/frontend/src/views/chart/components/senior/dialog/TrendLineEdit.vue @@ -0,0 +1,297 @@ + + + + + diff --git a/core/frontend/src/views/chart/view/ChartEdit.vue b/core/frontend/src/views/chart/view/ChartEdit.vue index 2405604eed..4cfae1f959 100644 --- a/core/frontend/src/views/chart/view/ChartEdit.vue +++ b/core/frontend/src/views/chart/view/ChartEdit.vue @@ -1344,6 +1344,18 @@ @onThresholdChange="onThresholdChange" /> + + + @@ -1918,6 +1930,8 @@ import CalcChartFieldEdit from '@/views/chart/view/CalcChartFieldEdit' import { equalsAny, includesAny } from '@/utils/StringUtils' import PositionAdjust from '@/views/chart/view/PositionAdjust' import MarkMapDataEditor from '@/views/chart/components/map/MarkMapDataEditor' +import TrendLine from '@/views/chart/components/senior/TrendLine' + export default { name: 'ChartEdit', components: { @@ -1955,7 +1969,8 @@ export default { DrillPath, PluginCom, MapMapping, - MarkMapDataEditor + MarkMapDataEditor, + TrendLine }, provide() { return { @@ -2021,6 +2036,7 @@ export default { senior: { functionCfg: DEFAULT_FUNCTION_CFG, assistLine: [], + trendLine: [], threshold: DEFAULT_THRESHOLD }, customFilter: {}, @@ -2166,6 +2182,9 @@ export default { showAssistLineCfg() { return includesAny(this.view.type, 'bar', 'line', 'area', 'mix') || this.view.type === 'scatter' }, + showTrendLineCfg() { + return this.view.render === 'antv' && equalsAny(this.view.type, 'line') + }, showThresholdCfg() { if (this.view.type === 'bidirectional-bar') { return false @@ -3040,12 +3059,15 @@ export default { this.view.senior.assistLine = val this.calcData() }, + onTrendLineChange(val) { + this.view.senior.trendLine = val + this.calcData() + }, onThresholdChange(val) { this.view.senior.threshold = val this.calcData() }, - onScrollChange(val) { this.view.senior.scrollCfg = val this.calcStyle()