diff --git a/core/core-frontend/src/views/chart/components/js/panel/charts/g2/distribution/radar.ts b/core/core-frontend/src/views/chart/components/js/panel/charts/g2/distribution/radar.ts index 6049c88d8e..692dfb0758 100644 --- a/core/core-frontend/src/views/chart/components/js/panel/charts/g2/distribution/radar.ts +++ b/core/core-frontend/src/views/chart/components/js/panel/charts/g2/distribution/radar.ts @@ -1,445 +1,445 @@ -import { flow, hexColorToRGBA, parseJson } from '@/views/chart/components/js/util' -import { valueFormatter } from '@/views/chart/components/js/formatter' -import { useI18n } from '@/hooks/web/useI18n' -import { defaultsDeep, isEmpty } from 'lodash-es' -import { DEFAULT_LABEL } from '@/views/chart/components/editor/util/chart' -import { Chart as G2Chart, G2Spec } from '@antv/g2' -import { G2ChartView, G2DrawOptions } from '../../../types/impl/g2' -import { TOOLTIP_ITEM_TPL, TOOLTIP_TITLE_TPL } from '../../../common/common_antv' - -const { t } = useI18n() - -export class Radar extends G2ChartView { - properties: EditorProperty[] = [ - 'background-overall-component', - 'border-style', - 'basic-style-selector', - 'label-selector', - 'tooltip-selector', - 'title-selector', - 'legend-selector', - 'misc-style-selector', - 'jump-set', - 'linkage' - ] - propertyInner: EditorPropertyInner = { - 'basic-style-selector': [ - 'colors', - 'alpha', - 'radarShape', - 'seriesColor', - 'radarShowPoint', - 'radarPointSize', - 'radarAreaColor' - ], - 'label-selector': ['seriesLabelFormatter'], - 'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'seriesTooltipFormatter', 'show'], - 'misc-style-selector': ['showName', 'color', 'fontSize', 'axisColor', 'axisValue'], - 'title-selector': [ - 'show', - 'title', - 'fontSize', - 'color', - 'hPosition', - 'isItalic', - 'isBolder', - 'remarkShow', - 'fontFamily', - 'letterSpace', - 'fontShadow' - ], - 'legend-selector': ['icon', 'orient', 'color', 'fontSize', 'hPosition', 'vPosition'] - } - selectorSpec: EditorSelectorSpec = { - ...this['selectorSpec'], - 'misc-style-selector': { - title: `${t('chart.tooltip_axis')}` - } - } - axis: AxisType[] = ['xAxis', 'yAxis', 'drill', 'filter', 'extLabel', 'extTooltip'] - axisConfig: AxisConfig = { - xAxis: { - name: `${t('chart.drag_block_radar_label')} / ${t('chart.dimension')}`, - type: 'd' - }, - yAxis: { - name: `${t('chart.drag_block_radar_length')} / ${t('chart.quota')}`, - type: 'q' - } - } - - async drawChart(drawOptions: G2DrawOptions): Promise { - const { chart, container, action } = drawOptions - if (!chart.data?.data) { - return - } - const data = chart.data.data - const baseOptions: G2Spec = { - type: 'view', - autoFit: true, - data, - coordinate: { type: 'polar' }, - children: [{ zIndex: 1, type: 'line', style: { lineWidth: 2 } }], - encode: { - x: 'field', - y: 'value', - color: 'category' - }, - scale: { - x: { - padding: 0.5, - align: 0 - }, - y: { - nice: true - } - } - } - const options = this.setupOptions(chart, baseOptions) - const newChart = new G2Chart({ container }) - newChart.options(options) - newChart.on('point:click', action) - if (options.children[0].labels?.length) { - newChart.on('label:click', e => { - action({ - x: e.x, - y: e.y, - data: { - data: e.target.attrs.data - } - }) - }) - } - return newChart - } - - protected configTheme(chart: Chart, options: G2Spec): G2Spec { - const customAttr = parseJson(chart.customAttr) - const colors: string[] = [] - if (customAttr.basicStyle) { - const basicStyle = customAttr.basicStyle - basicStyle.colors.forEach(ele => { - colors.push(hexColorToRGBA(ele, basicStyle.alpha)) - }) - } - const customStyle = parseJson(chart.customStyle) - let bgColor - if (customStyle.background) { - bgColor = hexColorToRGBA(customStyle.background.color, customStyle.background.alpha) - } - const theme = { - color: colors[0], - category10: colors, - category20: colors, - view: { - viewFill: bgColor - } - } - return { ...options, theme } - } - - protected configColor(chart: Chart, options: G2Spec): G2Spec { - const basicStyle = parseJson(chart.customAttr).basicStyle - const { seriesColor } = basicStyle - if (seriesColor?.length) { - const { yAxis } = chart - const seriesMap = seriesColor.reduce((p, n) => { - p[n.id] = n - return p - }, {}) - const colorRelations = [] - yAxis?.forEach(axis => { - const curAxisColor = seriesMap[axis.id] - if (curAxisColor) { - colorRelations.push([ - axis.name ?? axis.chartShowName, - hexColorToRGBA(curAxisColor.color, basicStyle.alpha) - ]) - } - }) - if (colorRelations.length) { - defaultsDeep(options, { - scale: { - color: { - relations: colorRelations - } - } - }) - } - } - return options - } - - protected configBasicStyle(chart: Chart, options: G2Spec): G2Spec { - const { radarShowPoint, radarPointSize, radarAreaColor } = parseJson( - chart.customAttr - ).basicStyle - - if (radarShowPoint) { - options.children.push({ - type: 'point', - encode: { - shape: 'point', - size: radarPointSize - }, - tooltip: false - }) - } - if (radarAreaColor) { - options.children.push({ - type: 'area', - style: { - opacity: 0.5 - }, - tooltip: false - }) - } - return options - } - - protected configLabel(chart: Chart, options: G2Spec): G2Spec { - const labelAttr = parseJson(chart.customAttr).label - if (!labelAttr.show) { - return options - } - const formatterMap = labelAttr.seriesLabelFormatter?.reduce((pre, next) => { - pre[next.id] = next - return pre - }, {}) - const lineMark = options.children[0] - const label = { - text: 'value', - transform: labelAttr.fullDisplay === true ? [] : [{ type: 'overlapHide' }], - style: { - fill: data => { - const color = DEFAULT_LABEL.color - if (!labelAttr.seriesLabelFormatter?.length) { - return color - } - const labelCfg = formatterMap?.[data.quotaList[0].id] as SeriesFormatter - if (!labelCfg?.show) { - return color - } - return labelCfg.color - }, - fontSize: data => { - const fontSize = DEFAULT_LABEL.fontSize - if (!labelAttr.seriesLabelFormatter?.length) { - return fontSize - } - const labelCfg = formatterMap?.[data.quotaList[0].id] as SeriesFormatter - if (!labelCfg?.show) { - return fontSize - } - return labelCfg.fontSize - }, - opacity: 1 - }, - formatter: (value, data) => { - if (!labelAttr.seriesLabelFormatter?.length) { - return value - } - const labelCfg = formatterMap?.[data.quotaList[0].id] as SeriesFormatter - if (!labelCfg) { - return value - } - if (!labelCfg.show) { - return '' - } - const result = valueFormatter(value, labelCfg.formatterCfg) - return result - } - } - lineMark.labels = [label] - return options - } - - protected configAxis(chart: Chart, options: G2Spec): G2Spec { - const customAttr = parseJson(chart.customAttr) - const customStyle = parseJson(chart.customStyle) - const basicStyle = customAttr.basicStyle - const misc = customStyle.misc - const axis = { - axis: { - x: { - grid: true, - tick: true, - tickLength: 10, - tickStrokeOpacity: 0, - label: misc.showName, - labelFill: misc.color, - labelFontSize: misc.fontSize, - labelAlign: 'horizontal', - labelOpacity: 1, - gridLineDash: [0, 0], - gridStroke: misc.axisColor, - gridStrokeOpacity: 1, - gridLineWidth: 1 - }, - y: { - zIndex: -1, - title: false, - labelFilter: () => false, - gridConnect: basicStyle.radarShape === 'polygon' ? 'line' : undefined, - gridStroke: misc.axisColor, - gridStrokeOpacity: 1, - gridLineWidth: 1, - gridLineDash: [0, 0] - } - } - } - defaultsDeep(options, axis) - const axisValue = misc.axisValue - if (!axisValue?.auto) { - const yScale = { - scale: { - y: { - domainMin: axisValue.min, - domainMax: axisValue.max, - tickCount: axisValue.splitCount, - tickMethod: (min, max, count) => { - const step = (max - min) / count - const ticks = [] - for (let i = 0; i <= count; i++) { - ticks.push(min + step * i) - } - return ticks - } - } - } - } - defaultsDeep(options, yScale) - } - return options - } - - protected configLegend(chart: Chart, options: G2Spec): G2Spec { - const { legend } = parseJson(chart.customStyle) - if (!legend.show) { - return { ...options, legend: false } - } - const baseLegend = this.getLegend(chart) - const tmpLegend = { - legend: { - color: { - ...baseLegend, - itemMarkerSize: legend.size, - itemMarker: legend.icon - } - } - } - defaultsDeep(options, tmpLegend) - return options - } - - protected configTooltip(chart: Chart, options: G2Spec): G2Spec { - const customAttr: DeepPartial = parseJson(chart.customAttr) - const tooltipAttr = customAttr.tooltip - const yAxis = chart.yAxis - if (!tooltipAttr.show) { - return { - ...options, - tooltip: false - } - } - const formatterMap = tooltipAttr.seriesTooltipFormatter - ?.filter(i => i.show) - .reduce((pre, next) => { - pre[next.id] = next - return pre - }, {}) as Record - let g2TooltipWrapper = document.getElementById('G2-TOOLTIP-WRAPPER') - if (!g2TooltipWrapper) { - g2TooltipWrapper = document.createElement('div') - g2TooltipWrapper.id = 'G2-TOOLTIP-WRAPPER' - g2TooltipWrapper.style.position = 'absolute' - g2TooltipWrapper.style.pointerEvents = 'none' - g2TooltipWrapper.style.zIndex = '9999' - document.body.appendChild(g2TooltipWrapper) - } - const lineMark = options.children[0] - const tooltipOptions: G2Spec = { - tooltip: d => d, - interaction: { - tooltip: { - crosshairsLineDash: [4, 4], - mount: g2TooltipWrapper, - css: { - '.g2-tooltip': { - background: tooltipAttr.backgroundColor - }, - '.g2-tooltip-title': { - color: tooltipAttr.color, - 'font-size': `${tooltipAttr.fontSize}px` - }, - '.g2-tooltip-list-item-name-label': { - color: tooltipAttr.color, - 'font-size': `${tooltipAttr.fontSize}px` - }, - '.g2-tooltip-list-item-value': { - color: tooltipAttr.color, - 'font-size': `${tooltipAttr.fontSize}px` - } - }, - render: (e, { title, items: originalItems }) => { - const titleHtml = TOOLTIP_TITLE_TPL.replace('{title}', title) - let tooltipItems = originalItems - if (tooltipAttr.seriesTooltipFormatter?.length) { - tooltipItems = originalItems.filter(item => formatterMap[item.quotaList[0].id]) - } - const result = [] - const head = originalItems[0] - tooltipItems.forEach(item => { - const formatter = formatterMap[item.quotaList[0].id] ?? yAxis[0] - const value = valueFormatter(item.value, formatter.formatterCfg) - const name = isEmpty(formatter.chartShowName) - ? formatter.name - : formatter.chartShowName - result.push({ ...item, name, value }) - }) - head.dynamicTooltipValue?.forEach(item => { - const formatter = formatterMap[item.fieldId] - if (formatter) { - const value = valueFormatter(parseFloat(item.value), formatter.formatterCfg) - const name = isEmpty(formatter.chartShowName) - ? formatter.name - : formatter.chartShowName - result.push({ color: 'grey', name, value }) - } - }) - const itemsHtml = result - .map(item => { - const marker = item.color - const label = item.name - const value = item.value - return TOOLTIP_ITEM_TPL.replace('{marker}', marker) - .replace('{label}', label) - .replace('{value}', value) - }) - .join('') - const listHtml = `
    ${itemsHtml}
` - return `${titleHtml}${listHtml}` - } - } - } - } - defaultsDeep(lineMark, tooltipOptions) - return options - } - - protected setupOptions(chart: Chart, options: G2Spec): G2Spec { - return flow( - this.configTheme, - this.configColor, - this.configLabel, - this.configLegend, - this.configTooltip, - this.configAxis, - this.configBasicStyle - )(chart, options, {}, this) - } - - constructor() { - super('radar', []) - } -} +import { flow, hexColorToRGBA, parseJson } from '@/views/chart/components/js/util' +import { valueFormatter } from '@/views/chart/components/js/formatter' +import { useI18n } from '@/hooks/web/useI18n' +import { defaultsDeep, isEmpty } from 'lodash-es' +import { DEFAULT_LABEL } from '@/views/chart/components/editor/util/chart' +import { Chart as G2Chart, G2Spec } from '@antv/g2' +import { G2ChartView, G2DrawOptions } from '../../../types/impl/g2' +import { TOOLTIP_ITEM_TPL, TOOLTIP_TITLE_TPL } from '../../../common/common_antv' + +const { t } = useI18n() + +export class Radar extends G2ChartView { + properties: EditorProperty[] = [ + 'background-overall-component', + 'border-style', + 'basic-style-selector', + 'label-selector', + 'tooltip-selector', + 'title-selector', + 'legend-selector', + 'misc-style-selector', + 'jump-set', + 'linkage' + ] + propertyInner: EditorPropertyInner = { + 'basic-style-selector': [ + 'colors', + 'alpha', + 'radarShape', + 'seriesColor', + 'radarShowPoint', + 'radarPointSize', + 'radarAreaColor' + ], + 'label-selector': ['seriesLabelFormatter'], + 'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'seriesTooltipFormatter', 'show'], + 'misc-style-selector': ['showName', 'color', 'fontSize', 'axisColor', 'axisValue'], + 'title-selector': [ + 'show', + 'title', + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'remarkShow', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ], + 'legend-selector': ['icon', 'orient', 'color', 'fontSize', 'hPosition', 'vPosition'] + } + selectorSpec: EditorSelectorSpec = { + ...this['selectorSpec'], + 'misc-style-selector': { + title: `${t('chart.tooltip_axis')}` + } + } + axis: AxisType[] = ['xAxis', 'yAxis', 'drill', 'filter', 'extLabel', 'extTooltip'] + axisConfig: AxisConfig = { + xAxis: { + name: `${t('chart.drag_block_radar_label')} / ${t('chart.dimension')}`, + type: 'd' + }, + yAxis: { + name: `${t('chart.drag_block_radar_length')} / ${t('chart.quota')}`, + type: 'q' + } + } + + async drawChart(drawOptions: G2DrawOptions): Promise { + const { chart, container, action } = drawOptions + if (!chart.data?.data) { + return + } + const data = chart.data.data + const baseOptions: G2Spec = { + type: 'view', + autoFit: true, + data, + coordinate: { type: 'polar' }, + children: [{ zIndex: 1, type: 'line', style: { lineWidth: 2 } }], + encode: { + x: 'field', + y: 'value', + color: 'category' + }, + scale: { + x: { + padding: 0.5, + align: 0 + }, + y: { + nice: true + } + } + } + const options = this.setupOptions(chart, baseOptions) + const newChart = new G2Chart({ container }) + newChart.options(options) + newChart.on('point:click', action) + if (options.children[0].labels?.length) { + newChart.on('label:click', e => { + action({ + x: e.x, + y: e.y, + data: { + data: e.target.attrs.data + } + }) + }) + } + return newChart + } + + protected configTheme(chart: Chart, options: G2Spec): G2Spec { + const customAttr = parseJson(chart.customAttr) + const colors: string[] = [] + if (customAttr.basicStyle) { + const basicStyle = customAttr.basicStyle + basicStyle.colors.forEach(ele => { + colors.push(hexColorToRGBA(ele, basicStyle.alpha)) + }) + } + const customStyle = parseJson(chart.customStyle) + let bgColor + if (customStyle.background) { + bgColor = hexColorToRGBA(customStyle.background.color, customStyle.background.alpha) + } + const theme = { + color: colors[0], + category10: colors, + category20: colors, + view: { + viewFill: bgColor + } + } + return { ...options, theme } + } + + protected configColor(chart: Chart, options: G2Spec): G2Spec { + const basicStyle = parseJson(chart.customAttr).basicStyle + const { seriesColor } = basicStyle + if (seriesColor?.length) { + const { yAxis } = chart + const seriesMap = seriesColor.reduce((p, n) => { + p[n.id] = n + return p + }, {}) + const colorRelations = [] + yAxis?.forEach(axis => { + const curAxisColor = seriesMap[axis.id] + if (curAxisColor) { + colorRelations.push([ + axis.name ?? axis.chartShowName, + hexColorToRGBA(curAxisColor.color, basicStyle.alpha) + ]) + } + }) + if (colorRelations.length) { + defaultsDeep(options, { + scale: { + color: { + relations: colorRelations + } + } + }) + } + } + return options + } + + protected configBasicStyle(chart: Chart, options: G2Spec): G2Spec { + const { radarShowPoint, radarPointSize, radarAreaColor } = parseJson( + chart.customAttr + ).basicStyle + + if (radarShowPoint) { + options.children.push({ + type: 'point', + encode: { + shape: 'point', + size: radarPointSize + }, + tooltip: false + }) + } + if (radarAreaColor) { + options.children.push({ + type: 'area', + style: { + opacity: 0.5 + }, + tooltip: false + }) + } + return options + } + + protected configLabel(chart: Chart, options: G2Spec): G2Spec { + const labelAttr = parseJson(chart.customAttr).label + if (!labelAttr.show) { + return options + } + const formatterMap = labelAttr.seriesLabelFormatter?.reduce((pre, next) => { + pre[next.id] = next + return pre + }, {}) + const lineMark = options.children[0] + const label = { + text: 'value', + transform: labelAttr.fullDisplay === true ? [] : [{ type: 'overlapHide' }], + style: { + fill: data => { + const color = DEFAULT_LABEL.color + if (!labelAttr.seriesLabelFormatter?.length) { + return color + } + const labelCfg = formatterMap?.[data.quotaList[0].id] as SeriesFormatter + if (!labelCfg?.show) { + return color + } + return labelCfg.color + }, + fontSize: data => { + const fontSize = DEFAULT_LABEL.fontSize + if (!labelAttr.seriesLabelFormatter?.length) { + return fontSize + } + const labelCfg = formatterMap?.[data.quotaList[0].id] as SeriesFormatter + if (!labelCfg?.show) { + return fontSize + } + return labelCfg.fontSize + }, + opacity: 1 + }, + formatter: (value, data) => { + if (!labelAttr.seriesLabelFormatter?.length) { + return value + } + const labelCfg = formatterMap?.[data.quotaList[0].id] as SeriesFormatter + if (!labelCfg) { + return value + } + if (!labelCfg.show) { + return '' + } + const result = valueFormatter(value, labelCfg.formatterCfg) + return result + } + } + lineMark.labels = [label] + return options + } + + protected configAxis(chart: Chart, options: G2Spec): G2Spec { + const customAttr = parseJson(chart.customAttr) + const customStyle = parseJson(chart.customStyle) + const basicStyle = customAttr.basicStyle + const misc = customStyle.misc + const axis = { + axis: { + x: { + grid: true, + tick: true, + tickLength: 10, + tickStrokeOpacity: 0, + label: misc.showName, + labelFill: misc.color, + labelFontSize: misc.fontSize, + labelAlign: 'horizontal', + labelOpacity: 1, + gridLineDash: [0, 0], + gridStroke: misc.axisColor, + gridStrokeOpacity: 1, + gridLineWidth: 1 + }, + y: { + zIndex: -1, + title: false, + labelFilter: () => false, + gridConnect: basicStyle.radarShape === 'polygon' ? 'line' : undefined, + gridStroke: misc.axisColor, + gridStrokeOpacity: 1, + gridLineWidth: 1, + gridLineDash: [0, 0] + } + } + } + defaultsDeep(options, axis) + const axisValue = misc.axisValue + if (!axisValue?.auto) { + const yScale = { + scale: { + y: { + domainMin: axisValue.min, + domainMax: axisValue.max, + tickCount: axisValue.splitCount, + tickMethod: (min, max, count) => { + const step = (max - min) / count + const ticks = [] + for (let i = 0; i <= count; i++) { + ticks.push(min + step * i) + } + return ticks + } + } + } + } + defaultsDeep(options, yScale) + } + return options + } + + protected configLegend(chart: Chart, options: G2Spec): G2Spec { + const { legend } = parseJson(chart.customStyle) + if (!legend.show) { + return { ...options, legend: false } + } + const baseLegend = this.getLegend(chart) + const tmpLegend = { + legend: { + color: { + ...baseLegend, + itemMarkerSize: legend.size, + itemMarker: legend.icon + } + } + } + defaultsDeep(options, tmpLegend) + return options + } + + protected configTooltip(chart: Chart, options: G2Spec): G2Spec { + const customAttr: DeepPartial = parseJson(chart.customAttr) + const tooltipAttr = customAttr.tooltip + const yAxis = chart.yAxis + if (!tooltipAttr.show) { + return { + ...options, + tooltip: false + } + } + const formatterMap = tooltipAttr.seriesTooltipFormatter + ?.filter(i => i.show) + .reduce((pre, next) => { + pre[next.id] = next + return pre + }, {}) as Record + let g2TooltipWrapper = document.getElementById('G2-TOOLTIP-WRAPPER') + if (!g2TooltipWrapper) { + g2TooltipWrapper = document.createElement('div') + g2TooltipWrapper.id = 'G2-TOOLTIP-WRAPPER' + g2TooltipWrapper.style.position = 'absolute' + g2TooltipWrapper.style.pointerEvents = 'none' + g2TooltipWrapper.style.zIndex = '9999' + document.body.appendChild(g2TooltipWrapper) + } + const lineMark = options.children[0] + const tooltipOptions: G2Spec = { + tooltip: d => d, + interaction: { + tooltip: { + crosshairsLineDash: [4, 4], + mount: g2TooltipWrapper, + css: { + '.g2-tooltip': { + background: tooltipAttr.backgroundColor + }, + '.g2-tooltip-title': { + color: tooltipAttr.color, + 'font-size': `${tooltipAttr.fontSize}px` + }, + '.g2-tooltip-list-item-name-label': { + color: tooltipAttr.color, + 'font-size': `${tooltipAttr.fontSize}px` + }, + '.g2-tooltip-list-item-value': { + color: tooltipAttr.color, + 'font-size': `${tooltipAttr.fontSize}px` + } + }, + render: (e, { title, items: originalItems }) => { + const titleHtml = TOOLTIP_TITLE_TPL.replace('{title}', title) + let tooltipItems = originalItems + if (tooltipAttr.seriesTooltipFormatter?.length) { + tooltipItems = originalItems.filter(item => formatterMap[item.quotaList[0].id]) + } + const result = [] + const head = originalItems[0] + tooltipItems.forEach(item => { + const formatter = formatterMap[item.quotaList[0].id] ?? yAxis[0] + const value = valueFormatter(item.value, formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) + ? formatter.name + : formatter.chartShowName + result.push({ ...item, name, value }) + }) + head.dynamicTooltipValue?.forEach(item => { + const formatter = formatterMap[item.fieldId] + if (formatter) { + const value = valueFormatter(parseFloat(item.value), formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) + ? formatter.name + : formatter.chartShowName + result.push({ color: 'grey', name, value }) + } + }) + const itemsHtml = result + .map(item => { + const marker = item.color + const label = item.name + const value = item.value + return TOOLTIP_ITEM_TPL.replace('{marker}', marker) + .replace('{label}', label) + .replace('{value}', value) + }) + .join('') + const listHtml = `
    ${itemsHtml}
` + return `${titleHtml}${listHtml}` + } + } + } + } + defaultsDeep(lineMark, tooltipOptions) + return options + } + + protected setupOptions(chart: Chart, options: G2Spec): G2Spec { + return flow( + this.configTheme, + this.configColor, + this.configLabel, + this.configLegend, + this.configTooltip, + this.configAxis, + this.configBasicStyle + )(chart, options, {}, this) + } + + constructor() { + super('radar', []) + } +} diff --git a/core/core-frontend/src/views/chart/components/js/panel/charts/g2/distribution/word-cloud.ts b/core/core-frontend/src/views/chart/components/js/panel/charts/g2/distribution/word-cloud.ts index 4767fa4e50..bcd88dfcb5 100644 --- a/core/core-frontend/src/views/chart/components/js/panel/charts/g2/distribution/word-cloud.ts +++ b/core/core-frontend/src/views/chart/components/js/panel/charts/g2/distribution/word-cloud.ts @@ -1,255 +1,255 @@ -import { - filterChartDataByRange, - flow, - getMaxAndMinValueByData, - hexColorToRGBA, - parseJson -} from '@/views/chart/components/js/util' -import { valueFormatter } from '@/views/chart/components/js/formatter' -import { useI18n } from '@/hooks/web/useI18n' -import { defaultsDeep, isEmpty } from 'lodash-es' -import { DEFAULT_MISC } from '@/views/chart/components/editor/util/chart' -import { Chart as G2Chart, G2Spec } from '@antv/g2' -import { G2ChartView, G2DrawOptions } from '../../../types/impl/g2' -import { TOOLTIP_ITEM_TPL, TOOLTIP_TITLE_TPL } from '../../../common/common_antv' - -const { t } = useI18n() -const DEFAULT_DATA = [] - -/** - * 词云图 - */ -export class WordCloud extends G2ChartView { - properties: EditorProperty[] = [ - 'basic-style-selector', - 'background-overall-component', - 'border-style', - 'title-selector', - 'tooltip-selector', - 'misc-selector', - 'jump-set', - 'linkage' - ] - propertyInner: EditorPropertyInner = { - 'background-overall-component': ['all'], - 'border-style': ['all'], - 'basic-style-selector': ['colors', 'alpha'], - 'title-selector': [ - 'title', - 'fontSize', - 'color', - 'hPosition', - 'isItalic', - 'isBolder', - 'remarkShow', - 'fontFamily', - 'letterSpace', - 'fontShadow' - ], - 'misc-selector': ['wordSizeRange', 'wordSpacing', 'wordCloudAxisValueRange'], - 'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'seriesTooltipFormatter', 'show'] - } - axis: AxisType[] = ['xAxis', 'yAxis', 'filter'] - axisConfig: AxisConfig = { - xAxis: { - name: `${t('chart.drag_block_word_cloud_label')} / ${t('chart.dimension_or_quota')}`, - type: 'd', - limit: 1 - }, - yAxis: { - name: `${t('chart.drag_block_word_cloud_size')} / ${t('chart.quota')}`, - type: 'q', - limit: 1 - } - } - setDataRange = (action, maxValue, minValue) => { - action({ - from: 'word-cloud', - data: { - max: maxValue, - min: minValue - } - }) - } - async drawChart(drawOptions: G2DrawOptions): Promise { - const { chart, container, action } = drawOptions - if (chart?.data) { - // data - let data = chart.data.data - const { misc } = parseJson(chart.customAttr) - let minValue = 0 - let maxValue = 0 - if ( - !misc.wordCloudAxisValueRange?.auto && - misc.wordCloudAxisValueRange?.fieldId === chart.yAxis[0].id - ) { - minValue = misc.wordCloudAxisValueRange.min - maxValue = misc.wordCloudAxisValueRange.max - } - getMaxAndMinValueByData(data ?? [], 'value', maxValue, minValue, (max, min) => { - maxValue = max - minValue = min - }) - data = filterChartDataByRange(data ?? [], maxValue, minValue) - // options - const initOptions: G2Spec = { - data, - type: 'wordCloud', - autoFit: true, - layout: { - spiral: 'rectangular', - rotate: 0, - padding: misc.wordSpacing ?? DEFAULT_MISC.wordSpacing, - fontSize: misc.wordSizeRange ?? DEFAULT_MISC.wordSizeRange, - random: 0.5 - }, - encode: { - color: 'field', - size: 'value', - text: 'field' - }, - legend: false, - axis: false - } - const options = this.setupOptions(chart, initOptions) - const newChart = new G2Chart({ container }) - newChart.options(options) - newChart.on('click', () => { - this.setDataRange(action, maxValue, minValue) - }) - newChart.on('afterrender', () => { - this.setDataRange(action, maxValue, minValue) - }) - newChart.on('point:click', param => { - action({ x: param.x, y: param.y, data: { data: param.data.data.datum } }) - }) - return newChart - } - } - - protected configTheme(chart: Chart, options: G2Spec): G2Spec { - const customAttr = parseJson(chart.customAttr) - const colors: string[] = [] - if (customAttr.basicStyle) { - const basicStyle = customAttr.basicStyle - basicStyle.colors.forEach(ele => { - colors.push(hexColorToRGBA(ele, basicStyle.alpha)) - }) - } - const customStyle = parseJson(chart.customStyle) - let bgColor - if (customStyle.background) { - bgColor = hexColorToRGBA(customStyle.background.color, customStyle.background.alpha) - } - const theme = { - color: colors[0], - category10: colors, - category20: colors, - view: { - viewFill: bgColor - } - } - return { ...options, theme } - } - - protected configTooltip(chart: Chart, options: G2Spec): G2Spec { - const customAttr: DeepPartial = parseJson(chart.customAttr) - const tooltipAttr = customAttr.tooltip - const yAxis = chart.yAxis - if (!tooltipAttr.show) { - return { - ...options, - tooltip: false - } - } - const formatterMap = tooltipAttr.seriesTooltipFormatter - ?.filter(i => i.show) - .reduce((pre, next) => { - pre[next.id] = next - return pre - }, {}) as Record - let g2TooltipWrapper = document.getElementById('G2-TOOLTIP-WRAPPER') - if (!g2TooltipWrapper) { - g2TooltipWrapper = document.createElement('div') - g2TooltipWrapper.id = 'G2-TOOLTIP-WRAPPER' - g2TooltipWrapper.style.position = 'absolute' - g2TooltipWrapper.style.pointerEvents = 'none' - g2TooltipWrapper.style.zIndex = '9999' - document.body.appendChild(g2TooltipWrapper) - } - const tooltipOptions: G2Spec = { - tooltip: d => d, - interaction: { - tooltip: { - mount: g2TooltipWrapper, - css: { - '.g2-tooltip': { - background: tooltipAttr.backgroundColor - }, - '.g2-tooltip-title': { - color: tooltipAttr.color, - 'font-size': `${tooltipAttr.fontSize}px` - }, - '.g2-tooltip-list-item-name-label': { - color: tooltipAttr.color, - 'font-size': `${tooltipAttr.fontSize}px` - }, - '.g2-tooltip-list-item-value': { - color: tooltipAttr.color, - 'font-size': `${tooltipAttr.fontSize}px` - } - }, - render: (e, { title, items: originalItems }) => { - const titleHtml = TOOLTIP_TITLE_TPL.replace('{title}', title) - let tooltipItems = originalItems - if (tooltipAttr.seriesTooltipFormatter?.length) { - tooltipItems = originalItems.filter(item => formatterMap[item.quotaList[0].id]) - } - const result = [] - const head = originalItems[0] - tooltipItems.forEach(item => { - const formatter = formatterMap[item.quotaList[0].id] ?? yAxis[0] - const value = valueFormatter(item.value, formatter.formatterCfg) - const name = isEmpty(formatter.chartShowName) - ? formatter.name - : formatter.chartShowName - result.push({ ...item, name, value }) - }) - head.dynamicTooltipValue?.forEach(item => { - const formatter = formatterMap[item.fieldId] - if (formatter) { - const value = valueFormatter(parseFloat(item.value), formatter.formatterCfg) - const name = isEmpty(formatter.chartShowName) - ? formatter.name - : formatter.chartShowName - result.push({ color: 'grey', name, value }) - } - }) - const itemsHtml = result - .map(item => { - const marker = item.color - const label = item.name - const value = item.value - return TOOLTIP_ITEM_TPL.replace('{marker}', marker) - .replace('{label}', label) - .replace('{value}', value) - }) - .join('') - const listHtml = `
    ${itemsHtml}
` - return `${titleHtml}${listHtml}` - } - } - } - } - defaultsDeep(options, tooltipOptions) - return options - } - - protected setupOptions(chart: Chart, options: G2Spec): G2Spec { - return flow(this.configTooltip)(chart, options) - } - - constructor() { - super('word-cloud', DEFAULT_DATA) - } -} +import { + filterChartDataByRange, + flow, + getMaxAndMinValueByData, + hexColorToRGBA, + parseJson +} from '@/views/chart/components/js/util' +import { valueFormatter } from '@/views/chart/components/js/formatter' +import { useI18n } from '@/hooks/web/useI18n' +import { defaultsDeep, isEmpty } from 'lodash-es' +import { DEFAULT_MISC } from '@/views/chart/components/editor/util/chart' +import { Chart as G2Chart, G2Spec } from '@antv/g2' +import { G2ChartView, G2DrawOptions } from '../../../types/impl/g2' +import { TOOLTIP_ITEM_TPL, TOOLTIP_TITLE_TPL } from '../../../common/common_antv' + +const { t } = useI18n() +const DEFAULT_DATA = [] + +/** + * 词云图 + */ +export class WordCloud extends G2ChartView { + properties: EditorProperty[] = [ + 'basic-style-selector', + 'background-overall-component', + 'border-style', + 'title-selector', + 'tooltip-selector', + 'misc-selector', + 'jump-set', + 'linkage' + ] + propertyInner: EditorPropertyInner = { + 'background-overall-component': ['all'], + 'border-style': ['all'], + 'basic-style-selector': ['colors', 'alpha'], + 'title-selector': [ + 'title', + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'remarkShow', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ], + 'misc-selector': ['wordSizeRange', 'wordSpacing', 'wordCloudAxisValueRange'], + 'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'seriesTooltipFormatter', 'show'] + } + axis: AxisType[] = ['xAxis', 'yAxis', 'filter'] + axisConfig: AxisConfig = { + xAxis: { + name: `${t('chart.drag_block_word_cloud_label')} / ${t('chart.dimension_or_quota')}`, + type: 'd', + limit: 1 + }, + yAxis: { + name: `${t('chart.drag_block_word_cloud_size')} / ${t('chart.quota')}`, + type: 'q', + limit: 1 + } + } + setDataRange = (action, maxValue, minValue) => { + action({ + from: 'word-cloud', + data: { + max: maxValue, + min: minValue + } + }) + } + async drawChart(drawOptions: G2DrawOptions): Promise { + const { chart, container, action } = drawOptions + if (chart?.data) { + // data + let data = chart.data.data + const { misc } = parseJson(chart.customAttr) + let minValue = 0 + let maxValue = 0 + if ( + !misc.wordCloudAxisValueRange?.auto && + misc.wordCloudAxisValueRange?.fieldId === chart.yAxis[0].id + ) { + minValue = misc.wordCloudAxisValueRange.min + maxValue = misc.wordCloudAxisValueRange.max + } + getMaxAndMinValueByData(data ?? [], 'value', maxValue, minValue, (max, min) => { + maxValue = max + minValue = min + }) + data = filterChartDataByRange(data ?? [], maxValue, minValue) + // options + const initOptions: G2Spec = { + data, + type: 'wordCloud', + autoFit: true, + layout: { + spiral: 'rectangular', + rotate: 0, + padding: misc.wordSpacing ?? DEFAULT_MISC.wordSpacing, + fontSize: misc.wordSizeRange ?? DEFAULT_MISC.wordSizeRange, + random: 0.5 + }, + encode: { + color: 'field', + size: 'value', + text: 'field' + }, + legend: false, + axis: false + } + const options = this.setupOptions(chart, initOptions) + const newChart = new G2Chart({ container }) + newChart.options(options) + newChart.on('click', () => { + this.setDataRange(action, maxValue, minValue) + }) + newChart.on('afterrender', () => { + this.setDataRange(action, maxValue, minValue) + }) + newChart.on('point:click', param => { + action({ x: param.x, y: param.y, data: { data: param.data.data.datum } }) + }) + return newChart + } + } + + protected configTheme(chart: Chart, options: G2Spec): G2Spec { + const customAttr = parseJson(chart.customAttr) + const colors: string[] = [] + if (customAttr.basicStyle) { + const basicStyle = customAttr.basicStyle + basicStyle.colors.forEach(ele => { + colors.push(hexColorToRGBA(ele, basicStyle.alpha)) + }) + } + const customStyle = parseJson(chart.customStyle) + let bgColor + if (customStyle.background) { + bgColor = hexColorToRGBA(customStyle.background.color, customStyle.background.alpha) + } + const theme = { + color: colors[0], + category10: colors, + category20: colors, + view: { + viewFill: bgColor + } + } + return { ...options, theme } + } + + protected configTooltip(chart: Chart, options: G2Spec): G2Spec { + const customAttr: DeepPartial = parseJson(chart.customAttr) + const tooltipAttr = customAttr.tooltip + const yAxis = chart.yAxis + if (!tooltipAttr.show) { + return { + ...options, + tooltip: false + } + } + const formatterMap = tooltipAttr.seriesTooltipFormatter + ?.filter(i => i.show) + .reduce((pre, next) => { + pre[next.id] = next + return pre + }, {}) as Record + let g2TooltipWrapper = document.getElementById('G2-TOOLTIP-WRAPPER') + if (!g2TooltipWrapper) { + g2TooltipWrapper = document.createElement('div') + g2TooltipWrapper.id = 'G2-TOOLTIP-WRAPPER' + g2TooltipWrapper.style.position = 'absolute' + g2TooltipWrapper.style.pointerEvents = 'none' + g2TooltipWrapper.style.zIndex = '9999' + document.body.appendChild(g2TooltipWrapper) + } + const tooltipOptions: G2Spec = { + tooltip: d => d, + interaction: { + tooltip: { + mount: g2TooltipWrapper, + css: { + '.g2-tooltip': { + background: tooltipAttr.backgroundColor + }, + '.g2-tooltip-title': { + color: tooltipAttr.color, + 'font-size': `${tooltipAttr.fontSize}px` + }, + '.g2-tooltip-list-item-name-label': { + color: tooltipAttr.color, + 'font-size': `${tooltipAttr.fontSize}px` + }, + '.g2-tooltip-list-item-value': { + color: tooltipAttr.color, + 'font-size': `${tooltipAttr.fontSize}px` + } + }, + render: (e, { title, items: originalItems }) => { + const titleHtml = TOOLTIP_TITLE_TPL.replace('{title}', title) + let tooltipItems = originalItems + if (tooltipAttr.seriesTooltipFormatter?.length) { + tooltipItems = originalItems.filter(item => formatterMap[item.quotaList[0].id]) + } + const result = [] + const head = originalItems[0] + tooltipItems.forEach(item => { + const formatter = formatterMap[item.quotaList[0].id] ?? yAxis[0] + const value = valueFormatter(item.value, formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) + ? formatter.name + : formatter.chartShowName + result.push({ ...item, name, value }) + }) + head.dynamicTooltipValue?.forEach(item => { + const formatter = formatterMap[item.fieldId] + if (formatter) { + const value = valueFormatter(parseFloat(item.value), formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) + ? formatter.name + : formatter.chartShowName + result.push({ color: 'grey', name, value }) + } + }) + const itemsHtml = result + .map(item => { + const marker = item.color + const label = item.name + const value = item.value + return TOOLTIP_ITEM_TPL.replace('{marker}', marker) + .replace('{label}', label) + .replace('{value}', value) + }) + .join('') + const listHtml = `
    ${itemsHtml}
` + return `${titleHtml}${listHtml}` + } + } + } + } + defaultsDeep(options, tooltipOptions) + return options + } + + protected setupOptions(chart: Chart, options: G2Spec): G2Spec { + return flow(this.configTooltip)(chart, options) + } + + constructor() { + super('word-cloud', DEFAULT_DATA) + } +}