diff --git a/frontend/src/icons/svg/percentage-bar-stack.svg b/frontend/src/icons/svg/percentage-bar-stack.svg new file mode 100644 index 0000000000..8ca73b2aa2 --- /dev/null +++ b/frontend/src/icons/svg/percentage-bar-stack.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/lang/en.js b/frontend/src/lang/en.js index 3705a43288..2ade6d493b 100644 --- a/frontend/src/lang/en.js +++ b/frontend/src/lang/en.js @@ -1041,6 +1041,7 @@ export default { label_shadow: 'Label Shadow', label_shadow_color: 'Shadow Color', content_formatter: 'Content Format', + label_reserve_decimal_count: 'Reserve Decimal', inside: 'Inside', tooltip: 'Tips', tooltip_item: 'Data Item', @@ -1117,6 +1118,7 @@ export default { chart_card: 'KPI Card', chart_bar: 'Base Bar', chart_bar_stack: 'Stack Bar', + chart_percentage_bar_stack: 'Percentage Stack Bar', chart_bar_horizontal: 'Horizontal Bar', chart_bar_stack_horizontal: 'Stack Horizontal Bar', chart_line: 'Base Line', diff --git a/frontend/src/lang/tw.js b/frontend/src/lang/tw.js index 60d519697b..59fcb8d111 100644 --- a/frontend/src/lang/tw.js +++ b/frontend/src/lang/tw.js @@ -1038,6 +1038,7 @@ export default { circle: '圓形', label: '標簽', label_position: '標簽位置', + label_reserve_decimal_count: '保留小数', label_bg: '標簽背景', label_shadow: '標簽陰影', label_shadow_color: '陰影顏色', @@ -1117,6 +1118,7 @@ export default { chart_card: '指標卡', chart_bar: '基礎柱狀圖', chart_bar_stack: '堆疊柱狀圖', + chart_percentage_bar_stack: '百分比柱狀圖', chart_bar_horizontal: '橫嚮柱狀圖', chart_bar_stack_horizontal: '橫嚮堆疊柱狀圖', chart_line: '基礎摺線圖', diff --git a/frontend/src/lang/zh.js b/frontend/src/lang/zh.js index ce9c2f3be1..6da3fd3e87 100644 --- a/frontend/src/lang/zh.js +++ b/frontend/src/lang/zh.js @@ -1040,6 +1040,7 @@ export default { label_bg: '标签背景', label_shadow: '标签阴影', label_shadow_color: '阴影颜色', + label_reserve_decimal_count: '保留小数', content_formatter: '内容格式', inside: '内', tooltip: '提示', @@ -1116,6 +1117,7 @@ export default { chart_card: '指标卡', chart_bar: '基础柱状图', chart_bar_stack: '堆叠柱状图', + chart_percentage_bar_stack: '百分比柱状图', chart_bar_horizontal: '横向柱状图', chart_bar_stack_horizontal: '横向堆叠柱状图', chart_line: '基础折线图', diff --git a/frontend/src/views/chart/chart/bar/bar_antv.js b/frontend/src/views/chart/chart/bar/bar_antv.js index 65c5e8687b..9c73137ff7 100644 --- a/frontend/src/views/chart/chart/bar/bar_antv.js +++ b/frontend/src/views/chart/chart/bar/bar_antv.js @@ -93,6 +93,8 @@ export function baseBarOptionAntV(plot, container, chart, action, isGroup, isSta } else { delete options.isStack } + // 目前只有百分比堆叠柱状图需要这个属性,先直接在这边判断而不作为参数传过来 + options.isPercent = chart.type === 'percentage-bar-stack' // custom color options.color = antVCustomColor(chart) diff --git a/frontend/src/views/chart/chart/chart.js b/frontend/src/views/chart/chart/chart.js index 5849768991..d7c580b0c6 100644 --- a/frontend/src/views/chart/chart/chart.js +++ b/frontend/src/views/chart/chart/chart.js @@ -129,7 +129,8 @@ export const DEFAULT_LABEL = { suffix: '', // 单位后缀 decimalCount: 2, // 小数位数 thousandSeparator: true// 千分符 - } + }, + reserveDecimalCount: 2 // 百分比堆叠柱状图保留小数位数 } export const DEFAULT_TOOLTIP = { show: true, diff --git a/frontend/src/views/chart/chart/common/common_antv.js b/frontend/src/views/chart/chart/common/common_antv.js index d67c066803..33bf02c0fe 100644 --- a/frontend/src/views/chart/chart/common/common_antv.js +++ b/frontend/src/views/chart/chart/common/common_antv.js @@ -52,7 +52,7 @@ export function getTheme(chart) { } } - return { + const theme = { styleSheet: { brandColor: colors[0], paletteQualitative10: colors, @@ -102,6 +102,12 @@ export function getTheme(chart) { } } } + // 百分比堆叠柱状图需要取消 offset,因为在顶部类别占比较低的时候有可能会把标签挤出去 + // 并且视觉上也比较不舒服 + if (chart.type === 'percentage-bar-stack') { + theme.innerLabels.offset = 0 + } + return theme } // 通用label export function getLabel(chart) { @@ -148,27 +154,35 @@ export function getLabel(chart) { extStack = JSON.parse(JSON.stringify(chart.extStack)) } - if (chart.type === 'bar-stack' || chart.type === 'line-stack' || chart.type === 'bar-stack-horizontal') { + if (chart.type === 'bar-stack' || + chart.type === 'line-stack' || + chart.type === 'bar-stack-horizontal' || + chart.type === 'percentage-bar-stack' + ) { + let f if (extStack && extStack.length > 0) { - const f = yAxis[0] - if (f.formatterCfg) { - res = valueFormatter(param.value, f.formatterCfg) - } else { - res = valueFormatter(param.value, formatterItem) - } + f = yAxis[0] } else { for (let i = 0; i < yAxis.length; i++) { - const f = yAxis[i] - if (f.name === param.category) { - if (f.formatterCfg) { - res = valueFormatter(param.value, f.formatterCfg) - } else { - res = valueFormatter(param.value, formatterItem) - } + if (yAxis[i].name === param.category) { + f = yAxis[i] break } } } + if (!f) { + return res + } + if (!f.formatterCfg) { + f.formatterCfg = formatterItem + } + // 百分比堆叠柱状图保留小数处理 + if (chart.type === 'percentage-bar-stack') { + f.formatterCfg.type = 'percent' + f.formatterCfg.decimalCount = l.reserveDecimalCount + f.formatterCfg.thousandSeparator = false + } + res = valueFormatter(param.value, f.formatterCfg) } else if (chart.type === 'bar-group') { const f = yAxis[0] if (f.formatterCfg) { @@ -214,7 +228,7 @@ export function getTooltip(chart) { if (chart.type && chart.type !== 'waterfall') { tooltip.formatter = function(param) { let yAxis, extStack - let res + let res = param.value try { yAxis = JSON.parse(chart.yaxis) } catch (e) { @@ -227,29 +241,37 @@ export function getTooltip(chart) { } let obj - if (chart.type === 'bar-stack' || chart.type === 'line-stack' || chart.type === 'bar-stack-horizontal') { + if (chart.type === 'bar-stack' || + chart.type === 'line-stack' || + chart.type === 'bar-stack-horizontal' || + chart.type === 'percentage-bar-stack') { + let f if (extStack && extStack.length > 0) { obj = { name: param.category, value: param.value } - const f = yAxis[0] - if (f.formatterCfg) { - res = valueFormatter(param.value, f.formatterCfg) - } else { - res = valueFormatter(param.value, formatterItem) - } + f = yAxis[0] } else { obj = { name: param.category, value: param.value } for (let i = 0; i < yAxis.length; i++) { - const f = yAxis[i] - if (f.name === param.category) { - if (f.formatterCfg) { - res = valueFormatter(param.value, f.formatterCfg) - } else { - res = valueFormatter(param.value, formatterItem) - } + if (yAxis[i].name === param.category) { + f = yAxis[i] break } } } + if (!f) { + return res + } + if (!f.formatterCfg) { + f.formatterCfg = formatterItem + } + if (chart.type === 'percentage-bar-stack') { + // 保留小数位数和标签保持一致,这边拿一下标签的配置 + const l = JSON.parse(JSON.stringify(customAttr.label)) + f.formatterCfg.type = 'percent' + f.formatterCfg.decimalCount = l.reserveDecimalCount + f.formatterCfg.thousandSeparator = false + } + res = valueFormatter(param.value, f.formatterCfg) } else if (chart.type === 'word-cloud') { obj = { name: param.text, value: param.value } for (let i = 0; i < yAxis.length; i++) { @@ -311,7 +333,13 @@ export function getTooltip(chart) { } } } else { - tooltip = false + // 百分比堆叠柱状图隐藏 tooltip 设置 show 为 false 或者直接设置 tooltip 为 false 都无效,会变成分组显示, + // 需要将容器(container)或者内容框(showContent)设置为 false 或者 null 才可以隐藏 + if (chart.type === 'percentage-bar-stack') { + tooltip.showContent = false + } else { + tooltip = false + } } } } @@ -390,7 +418,8 @@ export function getLegend(chart) { offsetY: offsetY, marker: { symbol: legendSymbol - } + }, + radio: false // 柱状图图例的聚焦功能,默认先关掉 } } else { legend = false diff --git a/frontend/src/views/chart/chart/util.js b/frontend/src/views/chart/chart/util.js index 55678128c7..d81b716192 100644 --- a/frontend/src/views/chart/chart/util.js +++ b/frontend/src/views/chart/chart/util.js @@ -1168,6 +1168,87 @@ export const TYPE_CONFIGS = [ ] } }, + { + render: 'antv', + category: 'chart.chart_type_compare', + value: 'percentage-bar-stack', + title: 'chart.chart_percentage_bar_stack', + icon: 'percentage-bar-stack', + properties: [ + 'color-selector', + 'size-selector-ant-v', + 'label-selector-ant-v', + 'tooltip-selector-ant-v', + 'x-axis-selector-ant-v', + 'y-axis-selector-ant-v', + 'title-selector-ant-v', + 'legend-selector-ant-v' + ], + propertyInner: { + 'color-selector': [ + 'value', + 'colorPanel', + 'customColor', + 'alpha' + ], + 'size-selector-ant-v': [ + 'barDefault', + 'barGap' + ], + 'label-selector-ant-v': [ + 'show', + 'fontSize', + 'color', + 'position-v', + 'reserve-decimal-count' + ], + 'tooltip-selector-ant-v': [ + 'show', + 'textStyle' + ], + 'x-axis-selector-ant-v': [ + 'show', + 'position', + 'name', + 'nameTextStyle', + 'splitLine', + 'axisForm', + 'axisLabel' + ], + 'y-axis-selector-ant-v': [ + 'show', + 'position', + 'name', + 'nameTextStyle', + 'axisValue', + 'splitLine', + 'axisForm', + 'axisLabel' + ], + 'title-selector-ant-v': [ + 'show', + 'title', + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'remarkShow', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ], + 'legend-selector-ant-v': [ + 'show', + 'icon', + 'orient', + 'textStyle', + 'hPosition', + 'vPosition' + ] + } + }, + { render: 'antv', category: 'chart.chart_type_distribute', diff --git a/frontend/src/views/chart/components/ChartComponentG2.vue b/frontend/src/views/chart/components/ChartComponentG2.vue index a5ed4d4594..3d2cabcc25 100644 --- a/frontend/src/views/chart/components/ChartComponentG2.vue +++ b/frontend/src/views/chart/components/ChartComponentG2.vue @@ -196,6 +196,8 @@ export default { this.myChart = baseBarOptionAntV(this.myChart, this.chartId, chart, this.antVAction, true, false) } else if (chart.type === 'bar-stack') { this.myChart = baseBarOptionAntV(this.myChart, this.chartId, chart, this.antVAction, false, true) + } else if (chart.type === 'percentage-bar-stack') { + this.myChart = baseBarOptionAntV(this.myChart, this.chartId, chart, this.antVAction, false, true) } else if (chart.type === 'bar-horizontal') { this.myChart = hBaseBarOptionAntV(this.myChart, this.chartId, chart, this.antVAction, true, false) } else if (chart.type === 'bar-stack-horizontal') { diff --git a/frontend/src/views/chart/components/shape-attr/LabelSelectorAntV.vue b/frontend/src/views/chart/components/shape-attr/LabelSelectorAntV.vue index cb165b637e..d49c97bad9 100644 --- a/frontend/src/views/chart/components/shape-attr/LabelSelectorAntV.vue +++ b/frontend/src/views/chart/components/shape-attr/LabelSelectorAntV.vue @@ -29,6 +29,11 @@ + + + {{ option.name }} + + @@ -93,7 +98,7 @@ export default { } } }, - data() { + data: function() { return { labelForm: JSON.parse(JSON.stringify(DEFAULT_LABEL)), fontSize: [], @@ -115,7 +120,12 @@ export default { ], predefineColors: COLOR_PANEL, typeList: formatterType, - unitList: unitList + unitList: unitList, + reserveDecimalCountOptions: [ + { name: '取整', value: 0 }, + { name: '一位', value: 1 }, + { name: '两位', value: 2 } + ] } }, watch: { @@ -179,11 +189,17 @@ export default { this.labelPosition = this.labelPositionH } else if (type.includes('pie')) { this.labelPosition = this.labelPositionPie + } else if (type === 'percentage-bar-stack') { + // 百分比堆叠柱状图的标签位置为 top 的话最顶上的标签会看不到,这个是 G2plot 的 bug,所以这边暂时先把默认值设置为 middle + this.labelForm.position = 'middle' } else { this.labelPosition = this.labelPositionV } } }, + /* + 判断该属性是否应该出现在当前视图的标签属性编辑列表中 + */ showProperty(property) { return this.propertyInner.includes(property) }