forked from github/dataease
feat(图表-漏斗图): 支持展示转化率
This commit is contained in:
parent
9c605faf9e
commit
40c5884a96
@ -813,6 +813,11 @@ declare interface ChartLabelAttr {
|
||||
* 显示极值
|
||||
*/
|
||||
showExtremum?: boolean
|
||||
|
||||
/**
|
||||
* 转化率标签
|
||||
*/
|
||||
conversionTag: ConversionTagAtt
|
||||
}
|
||||
/**
|
||||
* 提示设置
|
||||
@ -1080,3 +1085,18 @@ declare interface CarouselAttr {
|
||||
*/
|
||||
intervalTime: number
|
||||
}
|
||||
|
||||
declare interface ConversionTagAtt {
|
||||
/**
|
||||
* 是否显示
|
||||
*/
|
||||
show: boolean
|
||||
/**
|
||||
* 文本
|
||||
*/
|
||||
text: string
|
||||
/**
|
||||
* 精度
|
||||
*/
|
||||
precision: number
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
import { computed, onMounted, PropType, reactive, ref, watch } from 'vue'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { COLOR_PANEL, DEFAULT_LABEL } from '@/views/chart/components/editor/util/chart'
|
||||
import { ElIcon, ElSpace } from 'element-plus-secondary'
|
||||
import { ElFormItem, ElIcon, ElInput, ElSpace } from 'element-plus-secondary'
|
||||
import { formatterType, unitType } from '../../../js/formatter'
|
||||
import { defaultsDeep, cloneDeep, intersection, union, defaultTo, map } from 'lodash-es'
|
||||
import { includesAny } from '../../util/StringUtils'
|
||||
@ -231,7 +231,8 @@ const state = reactive<{ labelForm: ChartLabelAttr | any }>({
|
||||
labelForm: {
|
||||
quotaLabelFormatter: DEFAULT_LABEL.quotaLabelFormatter,
|
||||
seriesLabelFormatter: [],
|
||||
labelFormatter: DEFAULT_LABEL.labelFormatter
|
||||
labelFormatter: DEFAULT_LABEL.labelFormatter,
|
||||
conversionTag: DEFAULT_LABEL.conversionTag
|
||||
}
|
||||
})
|
||||
|
||||
@ -255,6 +256,9 @@ const init = () => {
|
||||
}
|
||||
}
|
||||
const checkLabelContent = contentProp => {
|
||||
if (chartType.value === 'funnel') {
|
||||
return false
|
||||
}
|
||||
const propIntersection = intersection(props.propertyInner, [
|
||||
'showDimension',
|
||||
'showQuota',
|
||||
@ -373,6 +377,11 @@ onMounted(() => {
|
||||
const isGroupBar = computed(() => {
|
||||
return props.chart.type === 'bar-group'
|
||||
})
|
||||
const conversionPrecision = [
|
||||
{ name: t('chart.reserve_zero'), value: 0 },
|
||||
{ name: t('chart.reserve_one'), value: 1 },
|
||||
{ name: t('chart.reserve_two'), value: 2 }
|
||||
]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -1251,6 +1260,54 @@ const isGroupBar = computed(() => {
|
||||
{{ t('chart.show_gap') }}
|
||||
</el-checkbox>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
class="form-item"
|
||||
:class="'form-item-' + themes"
|
||||
v-if="showProperty('conversionTag')"
|
||||
>
|
||||
<el-checkbox
|
||||
:effect="themes"
|
||||
@change="changeLabelAttr('conversionTag')"
|
||||
v-model="state.labelForm.conversionTag.show"
|
||||
>
|
||||
转化率
|
||||
</el-checkbox>
|
||||
</el-form-item>
|
||||
<div style="padding-left: 22px">
|
||||
<el-row :gutter="8">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="保留小数" class="form-item" :class="'form-item-' + themes">
|
||||
<el-select
|
||||
size="small"
|
||||
style="width: 108px"
|
||||
:effect="themes"
|
||||
:disabled="!state.labelForm.conversionTag.show"
|
||||
v-model.number="state.labelForm.conversionTag.precision"
|
||||
@change="changeLabelAttr('conversionTag')"
|
||||
>
|
||||
<el-option
|
||||
v-for="option in conversionPrecision"
|
||||
:key="option.value"
|
||||
:label="option.name"
|
||||
:value="option.value"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-form-item label="转化率名称" class="form-item" :class="'form-item-' + themes">
|
||||
<el-input
|
||||
:effect="themes"
|
||||
v-model="state.labelForm.conversionTag.text"
|
||||
size="small"
|
||||
maxlength="100"
|
||||
:disabled="!state.labelForm.conversionTag.show"
|
||||
@blur="changeLabelAttr('conversionTag')"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</el-form>
|
||||
</template>
|
||||
|
||||
|
@ -324,7 +324,12 @@ export const DEFAULT_LABEL: ChartLabelAttr = {
|
||||
showDimension: true,
|
||||
showQuota: false,
|
||||
showProportion: true,
|
||||
seriesLabelFormatter: []
|
||||
seriesLabelFormatter: [],
|
||||
conversionTag: {
|
||||
show: false,
|
||||
precision: 2,
|
||||
text: '转化率'
|
||||
}
|
||||
}
|
||||
export const DEFAULT_TOOLTIP: ChartTooltipAttr = {
|
||||
show: true,
|
||||
|
@ -1,8 +1,10 @@
|
||||
import type { FunnelOptions, Funnel as G2Funnel } from '@antv/g2plot/esm/plots/funnel'
|
||||
import { G2PlotChartView, G2PlotDrawOptions } from '../../types/impl/g2plot'
|
||||
import { flow, setUpSingleDimensionSeriesColor } from '@/views/chart/components/js/util'
|
||||
import { flow, parseJson, setUpSingleDimensionSeriesColor } from '@/views/chart/components/js/util'
|
||||
import { getPadding } from '../../common/common_antv'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { Datum } from '@antv/g2plot/esm/types/common'
|
||||
import { valueFormatter } from '@/views/chart/components/js/formatter'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
@ -23,7 +25,7 @@ export class Funnel extends G2PlotChartView<FunnelOptions, G2Funnel> {
|
||||
propertyInner: EditorPropertyInner = {
|
||||
'background-overall-component': ['all'],
|
||||
'basic-style-selector': ['colors', 'alpha', 'seriesColor'],
|
||||
'label-selector': ['fontSize', 'color', 'hPosition', 'labelFormatter'],
|
||||
'label-selector': ['fontSize', 'color', 'hPosition', 'showQuota', 'conversionTag'],
|
||||
'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'seriesTooltipFormatter', 'show'],
|
||||
'title-selector': [
|
||||
'show',
|
||||
@ -64,7 +66,6 @@ export class Funnel extends G2PlotChartView<FunnelOptions, G2Funnel> {
|
||||
xField: 'field',
|
||||
yField: 'value',
|
||||
appendPadding: getPadding(chart),
|
||||
conversionTag: false,
|
||||
interactions: [
|
||||
{
|
||||
type: 'legend-active',
|
||||
@ -111,15 +112,58 @@ export class Funnel extends G2PlotChartView<FunnelOptions, G2Funnel> {
|
||||
}
|
||||
|
||||
protected configLabel(chart: Chart, options: FunnelOptions): FunnelOptions {
|
||||
const tmpOptions = super.configLabel(chart, options)
|
||||
if (!tmpOptions.label) {
|
||||
return tmpOptions
|
||||
let label
|
||||
let conversionTag
|
||||
let customAttr: DeepPartial<ChartAttr>
|
||||
if (chart.customAttr) {
|
||||
customAttr = parseJson(chart.customAttr)
|
||||
const showQuota = customAttr.label.showQuota
|
||||
const l = customAttr.label
|
||||
if (customAttr.label?.show) {
|
||||
// label
|
||||
if (showQuota) {
|
||||
label = {
|
||||
position: l.position,
|
||||
layout: [{ type: 'limit-in-canvas' }],
|
||||
style: {
|
||||
fill: l.color,
|
||||
fontSize: l.fontSize
|
||||
},
|
||||
formatter: function (param: Datum) {
|
||||
return valueFormatter(param.value, l.quotaLabelFormatter)
|
||||
}
|
||||
}
|
||||
const position = label.position
|
||||
if (position === 'right') {
|
||||
label.offsetX = -40
|
||||
}
|
||||
}
|
||||
// 转化率
|
||||
const conversionTagAtt = parseJson(chart.customAttr).label.conversionTag
|
||||
if (conversionTagAtt && conversionTagAtt.show) {
|
||||
conversionTag = {
|
||||
style: {
|
||||
fill: l.color,
|
||||
fontSize: l.fontSize
|
||||
},
|
||||
formatter: datum => {
|
||||
const rate = (
|
||||
(datum['$$conversion$$'][1] / datum['$$conversion$$'][0]) *
|
||||
100
|
||||
).toFixed(conversionTagAtt.precision)
|
||||
return `${conversionTagAtt.text ?? ''}${rate}%`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
...options,
|
||||
label,
|
||||
conversionTag,
|
||||
maxSize: conversionTag ? 0.8 : 1
|
||||
}
|
||||
}
|
||||
const position = tmpOptions.label.position
|
||||
if (position === 'right') {
|
||||
tmpOptions.label.offsetX = -40
|
||||
}
|
||||
return tmpOptions
|
||||
return options
|
||||
}
|
||||
|
||||
public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] {
|
||||
@ -142,7 +186,13 @@ export class Funnel extends G2PlotChartView<FunnelOptions, G2Funnel> {
|
||||
}
|
||||
customAttr.label = {
|
||||
...label,
|
||||
show: true
|
||||
show: true,
|
||||
showQuota: true,
|
||||
conversionTag: {
|
||||
show: false,
|
||||
precision: 2,
|
||||
text: '转化率'
|
||||
}
|
||||
}
|
||||
const { legend } = customStyle
|
||||
legend.show = false
|
||||
|
Loading…
Reference in New Issue
Block a user