forked from github/dataease
feat(图表-漏斗图): 支持展示转化率
This commit is contained in:
parent
9c605faf9e
commit
40c5884a96
@ -813,6 +813,11 @@ declare interface ChartLabelAttr {
|
|||||||
* 显示极值
|
* 显示极值
|
||||||
*/
|
*/
|
||||||
showExtremum?: boolean
|
showExtremum?: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 转化率标签
|
||||||
|
*/
|
||||||
|
conversionTag: ConversionTagAtt
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 提示设置
|
* 提示设置
|
||||||
@ -1080,3 +1085,18 @@ declare interface CarouselAttr {
|
|||||||
*/
|
*/
|
||||||
intervalTime: number
|
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 { computed, onMounted, PropType, reactive, ref, watch } from 'vue'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
import { useI18n } from '@/hooks/web/useI18n'
|
||||||
import { COLOR_PANEL, DEFAULT_LABEL } from '@/views/chart/components/editor/util/chart'
|
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 { formatterType, unitType } from '../../../js/formatter'
|
||||||
import { defaultsDeep, cloneDeep, intersection, union, defaultTo, map } from 'lodash-es'
|
import { defaultsDeep, cloneDeep, intersection, union, defaultTo, map } from 'lodash-es'
|
||||||
import { includesAny } from '../../util/StringUtils'
|
import { includesAny } from '../../util/StringUtils'
|
||||||
@ -231,7 +231,8 @@ const state = reactive<{ labelForm: ChartLabelAttr | any }>({
|
|||||||
labelForm: {
|
labelForm: {
|
||||||
quotaLabelFormatter: DEFAULT_LABEL.quotaLabelFormatter,
|
quotaLabelFormatter: DEFAULT_LABEL.quotaLabelFormatter,
|
||||||
seriesLabelFormatter: [],
|
seriesLabelFormatter: [],
|
||||||
labelFormatter: DEFAULT_LABEL.labelFormatter
|
labelFormatter: DEFAULT_LABEL.labelFormatter,
|
||||||
|
conversionTag: DEFAULT_LABEL.conversionTag
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -255,6 +256,9 @@ const init = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const checkLabelContent = contentProp => {
|
const checkLabelContent = contentProp => {
|
||||||
|
if (chartType.value === 'funnel') {
|
||||||
|
return false
|
||||||
|
}
|
||||||
const propIntersection = intersection(props.propertyInner, [
|
const propIntersection = intersection(props.propertyInner, [
|
||||||
'showDimension',
|
'showDimension',
|
||||||
'showQuota',
|
'showQuota',
|
||||||
@ -373,6 +377,11 @@ onMounted(() => {
|
|||||||
const isGroupBar = computed(() => {
|
const isGroupBar = computed(() => {
|
||||||
return props.chart.type === 'bar-group'
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -1251,6 +1260,54 @@ const isGroupBar = computed(() => {
|
|||||||
{{ t('chart.show_gap') }}
|
{{ t('chart.show_gap') }}
|
||||||
</el-checkbox>
|
</el-checkbox>
|
||||||
</el-form-item>
|
</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>
|
</el-form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -324,7 +324,12 @@ export const DEFAULT_LABEL: ChartLabelAttr = {
|
|||||||
showDimension: true,
|
showDimension: true,
|
||||||
showQuota: false,
|
showQuota: false,
|
||||||
showProportion: true,
|
showProportion: true,
|
||||||
seriesLabelFormatter: []
|
seriesLabelFormatter: [],
|
||||||
|
conversionTag: {
|
||||||
|
show: false,
|
||||||
|
precision: 2,
|
||||||
|
text: '转化率'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
export const DEFAULT_TOOLTIP: ChartTooltipAttr = {
|
export const DEFAULT_TOOLTIP: ChartTooltipAttr = {
|
||||||
show: true,
|
show: true,
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import type { FunnelOptions, Funnel as G2Funnel } from '@antv/g2plot/esm/plots/funnel'
|
import type { FunnelOptions, Funnel as G2Funnel } from '@antv/g2plot/esm/plots/funnel'
|
||||||
import { G2PlotChartView, G2PlotDrawOptions } from '../../types/impl/g2plot'
|
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 { getPadding } from '../../common/common_antv'
|
||||||
import { useI18n } from '@/hooks/web/useI18n'
|
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()
|
const { t } = useI18n()
|
||||||
|
|
||||||
@ -23,7 +25,7 @@ export class Funnel extends G2PlotChartView<FunnelOptions, G2Funnel> {
|
|||||||
propertyInner: EditorPropertyInner = {
|
propertyInner: EditorPropertyInner = {
|
||||||
'background-overall-component': ['all'],
|
'background-overall-component': ['all'],
|
||||||
'basic-style-selector': ['colors', 'alpha', 'seriesColor'],
|
'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'],
|
'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'seriesTooltipFormatter', 'show'],
|
||||||
'title-selector': [
|
'title-selector': [
|
||||||
'show',
|
'show',
|
||||||
@ -64,7 +66,6 @@ export class Funnel extends G2PlotChartView<FunnelOptions, G2Funnel> {
|
|||||||
xField: 'field',
|
xField: 'field',
|
||||||
yField: 'value',
|
yField: 'value',
|
||||||
appendPadding: getPadding(chart),
|
appendPadding: getPadding(chart),
|
||||||
conversionTag: false,
|
|
||||||
interactions: [
|
interactions: [
|
||||||
{
|
{
|
||||||
type: 'legend-active',
|
type: 'legend-active',
|
||||||
@ -111,15 +112,58 @@ export class Funnel extends G2PlotChartView<FunnelOptions, G2Funnel> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected configLabel(chart: Chart, options: FunnelOptions): FunnelOptions {
|
protected configLabel(chart: Chart, options: FunnelOptions): FunnelOptions {
|
||||||
const tmpOptions = super.configLabel(chart, options)
|
let label
|
||||||
if (!tmpOptions.label) {
|
let conversionTag
|
||||||
return tmpOptions
|
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
|
return options
|
||||||
if (position === 'right') {
|
|
||||||
tmpOptions.label.offsetX = -40
|
|
||||||
}
|
|
||||||
return tmpOptions
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] {
|
public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] {
|
||||||
@ -142,7 +186,13 @@ export class Funnel extends G2PlotChartView<FunnelOptions, G2Funnel> {
|
|||||||
}
|
}
|
||||||
customAttr.label = {
|
customAttr.label = {
|
||||||
...label,
|
...label,
|
||||||
show: true
|
show: true,
|
||||||
|
showQuota: true,
|
||||||
|
conversionTag: {
|
||||||
|
show: false,
|
||||||
|
precision: 2,
|
||||||
|
text: '转化率'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const { legend } = customStyle
|
const { legend } = customStyle
|
||||||
legend.show = false
|
legend.show = false
|
||||||
|
Loading…
Reference in New Issue
Block a user