* 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, setArrayValue, cloneDeep } from '../chart-core/deps/utils'
import { itemPoint, itemLabel, itemContent } from '../chart-core/deps/constants'
import { isNull } from '@opentiny/utils'
const pieRadius = 100
const ringRadius = [90, 100]
const roseRingRadius = [20, 100]
const pieOffsetY = '50%'
const modifySeries = ({ series, limitShowNum, t }) => {
let firstSerie = series[0]
if (limitShowNum && limitShowNum < firstSerie.data.length) {
let firstSerieData = firstSerie.data
let remainArr = firstSerieData.slice(limitShowNum, firstSerieData.length)
let sum = 0
remainArr.forEach((item) => (sum += item.value))
firstSerie.data = firstSerieData.slice(0, limitShowNum)
firstSerie.data.push({ name: t('ui.chart.other'), value: sum })
}
}
const getPieSeries = (args) => {
const { dataType, digit, dimension, emphasis, innerRows, isRing, itemStyle, label, labelLine } = args
const { level, limitShowNum, metrics, offsetY, percentShow, radius, roseType, selectedMode, t } = args
let { series = [], levelTemp = {}, rowsTemp = [] } = {}
if (!level) {
rowsTemp.push(innerRows)
} else {
level.forEach((levelItems, index) => levelItems.forEach((item) => setArrayValue(levelTemp, item, index)))
innerRows.forEach((row) => {
let itemLevel = levelTemp[row[dimension]]
if (itemLevel && itemLevel.length) {
itemLevel.forEach((levelItem) => setArrayValue(rowsTemp, levelItem, row))
}
})
}
let serieBase = { type: 'pie', selectedMode, emphasis, roseType, center: ['50%', offsetY] }
let rowsCount = rowsTemp.length
let centerWidth = radius / rowsCount
rowsTemp.forEach((dataRows, index) => {
let serie = { data: [], ...serieBase }
if (!index) {
serie.radius = isRing ? radius : centerWidth
} else {
let outerWidth = centerWidth + (radius / (2 * rowsCount)) * (2 * index - 1)
let innerWidth = outerWidth + radius / (2 * rowsCount)
serie.radius = [outerWidth, innerWidth]
}
rowsCount > 1 && index === 0 && (serie.label = { position: 'inner' })
serie.label = { color: '#191919', ...label }
serie.labelLine = { smooth: true, lineStyle: { color: '#bbb' }, ...labelLine }
serie.itemStyle = { borderWidth: 2, borderColor: '#fff', ...itemStyle }
if (percentShow) {
let position = rowsCount > 1 && index === 0 ? 'inner' : 'outside'
let formatter = function (item) {
let tplt = []
tplt.push(`${item.name}:`)
tplt.push(getFormated(item.value, dataType, digit))
tplt.push(`(${item.percent}%)`)
return tplt.join('')
}
serie.label = { normal: { show: true, position, formatter } }
}
serie.data = dataRows.map((row) => ({ name: row[dimension], value: row[metrics] }))
series.push(serie)
})
modifySeries({ series, limitShowNum, t })
return series
}
const getPieLegend = (args) => {
const { dimension, innerRows, legendLimit, legendName, level, limitShowNum, t } = args
let { legend = [], levelTemp = [] } = {}
if (level) {
level.forEach((levelItem) => levelItem.forEach((item) => levelTemp.push(item)))
legend = levelTemp
} else if (limitShowNum && limitShowNum < innerRows.length) {
for (let i = limitShowNum - 1; i >= 0; i--) {
legend.unshift(innerRows[i][dimension])
}
legend.push(t('ui.chart.other'))
} else {
legend = innerRows.map((row) => row[dimension])
}
if (legend.length) {
let show = legend.length < legendLimit
let formatter = function (name) {
return !isNull(legendName[name]) ? legendName[name] : name
}
return { data: legend, show, formatter }
} else {
return false
}
}
const getPieTooltip = (args) => {
const { dataType, digit, dimension, innerRows, limitShowNum, metrics, t } = args
let { localeOther = t('ui.chart.other'), remainArr, sum = 0 } = {}
let mapHandler = (row) => {
sum += row[metrics]
return { name: row[dimension], value: row[metrics] }
}
remainArr = innerRows.map(mapHandler).slice(limitShowNum, innerRows.length)
let formatter = function (item) {
let tplt = [itemPoint(item.color)]
let percent
if (!limitShowNum || item.name !== localeOther) {
tplt.push(itemLabel(item.name))
tplt.push(itemContent(getFormated(item.value, dataType, digit)))
tplt.push(itemContent(`(${item.percent}%)`))
} else {
tplt.push(localeOther + ':')
remainArr.forEach(({ name, value }) => {
percent = getFormated(value / sum, 'percent')
tplt.push(`<br>${itemLabel(name)}`)
tplt.push(itemContent(getFormated(value, dataType, digit)))
tplt.push(itemContent(percent))
})
}
return tplt.join('')
}
return { formatter }
}
export const pie = (columns, rows, settings, extra, isRing) => {
const innerRows = cloneDeep(rows)
const { dataType = 'normal', digit = 2, dimension = columns[0], emphasis = { scale: true } } = settings
const { itemStyle, label = false, labelLine, legendLimit = 30, legendName = {}, level = false } = settings
const { limitShowNum = 0, metrics = columns[1], offsetY = pieOffsetY, percentShow } = settings
const { roseType = false, selectedMode = false } = settings
const { radius = isRing ? (roseType ? roseRingRadius : ringRadius) : pieRadius } = settings
const { legendVisible, t, tooltipVisible } = extra
limitShowNum && innerRows.sort((a, b) => b[metrics] - a[metrics])
const seriesParams = { dataType, digit, dimension, emphasis, innerRows, isRing, itemStyle }
Object.assign(seriesParams, { label, labelLine, legendName, level, limitShowNum, metrics, offsetY })
Object.assign(seriesParams, { percentShow, radius, roseType, selectedMode, t })
const series = getPieSeries(seriesParams)
const legendParams = { dimension, innerRows, legendLimit, legendName, level, limitShowNum, t }
const legend = legendVisible && getPieLegend(legendParams)
const pieTooltip = getPieTooltip({ dataType, innerRows, limitShowNum, digit, metrics, dimension, t })
const tooltip = tooltipVisible && pieTooltip
const options = { legend, series, tooltip }
return options
}
export const ring = (columns, rows, settings, extra) => pie(columns, rows, settings, extra, true)