* Copyright (c) 2022 - present TinyVue Authors.
* Copyright (c) 2022 - present Huawei Cloud Computing Technologies Co., Ltd.
*
* Use of this source code is governed by an MIT-style license.
*
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
*
*/
import { getFormated } from '../chart-core/deps/utils'
import { itemPoint, itemLabel, itemContent } from '../chart-core/deps/constants'
import { isNull } from '@opentiny/utils'
const getFunnelTooltip = (dataType, digit) => {
function formatter(item) {
let tpl = []
tpl.push(itemPoint(item.color))
tpl.push(`${itemLabel(item.name)}${itemContent(getFormated(item.data.realValue, dataType, digit))}`)
return tpl.join('')
}
return { trigger: 'item', formatter }
}
const getFunnelLegend = (args) => {
const { data, legendName } = args
function formatter(name) {
return isNull(legendName[name]) ? name : legendName[name]
}
return { data, formatter }
}
const getFunnelSeries = (args) => {
const { ascending, dimension, itemStyle, label, labelLine, metrics, rows, sequence, useDefaultOrder } = args
let { series = { type: 'funnel' }, falseFunnel = false } = {}
series.minSize = 8
let innerRows = rows.sort((a, b) => sequence.indexOf(a[dimension]) - sequence.indexOf(b[dimension]))
innerRows.some((row, index) => index && row[metrics] > innerRows[index - 1][metrics] && (falseFunnel = true))
const step = 100 / innerRows.length
if (falseFunnel && !useDefaultOrder) {
const handler = (row, index) => ({ name: row[dimension], value: (index + 1) * step, realValue: row[metrics] })
series.data = innerRows.slice().reverse().map(handler)
} else {
series.data = innerRows.map((row) => ({ name: row[dimension], value: row[metrics], realValue: row[metrics] }))
}
let total = 0
rows.forEach((row) => {
total += row[metrics]
})
series.label = {
position: 'inside',
color: '#fff',
formatter(item) {
let { value } = item
return `${Number(value / total).toFixed(2) * 100}%`
}
}
ascending && (series.sort = 'ascending')
label && (series.label = label)
labelLine && (series.labelLine = labelLine)
itemStyle && (series.itemStyle = itemStyle)
return series
}
export const funnel = (outerColumns, outerRows, settings, extra) => {
const { columns = outerColumns.slice(), rows = outerRows.slice() } = {}
const { dataType = 'normal', dimension = columns[0], sequence = rows.map((row) => row[dimension]) } = settings
const { digit = 2, ascending, label, labelLine, legendName = {}, itemStyle, filterZero, useDefaultOrder } = settings
const { tooltipVisible, legendVisible } = extra
let metrics
if (settings.metrics) {
metrics = settings.metrics
} else {
let temp = columns.slice()
temp.splice(columns.indexOf(dimension), 1)
metrics = temp[0]
}
let innerRows = rows.sort((a, b) => sequence.indexOf(a[dimension]) - sequence.indexOf(b[dimension]))
filterZero && (innerRows = innerRows.filter((row) => row[metrics]))
const tooltip = tooltipVisible && getFunnelTooltip(dataType, digit)
const legend = legendVisible && getFunnelLegend({ data: innerRows.map((row) => row[dimension]), legendName })
const seriesParam = { dimension, metrics, rows: innerRows, sequence, ascending }
Object.assign(seriesParam, { label, labelLine, itemStyle, filterZero, useDefaultOrder })
const series = getFunnelSeries(seriesParam)
return { tooltip, legend, series }
}