import {
|
G2PlotChartView,
|
G2PlotDrawOptions
|
} from '@/views/chart/components/js/panel/types/impl/g2plot'
|
import type { Liquid as G2Liquid, LiquidOptions } from '@antv/g2plot/esm/plots/liquid'
|
import { flow, hexColorToRGBA, parseJson } from '@/views/chart/components/js/util'
|
import { DEFAULT_MISC } from '@/views/chart/components/editor/util/chart'
|
import { valueFormatter } from '@/views/chart/components/js/formatter'
|
import { useI18n } from '@/hooks/web/useI18n'
|
import { defaultsDeep } from 'lodash-es'
|
|
const { t } = useI18n()
|
const DEFAULT_LIQUID_DATA = []
|
/**
|
* 水波图
|
*/
|
export class Liquid extends G2PlotChartView<LiquidOptions, G2Liquid> {
|
properties: EditorProperty[] = [
|
'background-overall-component',
|
'border-style',
|
'basic-style-selector',
|
'label-selector',
|
'misc-selector',
|
'title-selector',
|
'threshold'
|
]
|
propertyInner: EditorPropertyInner = {
|
'background-overall-component': ['all'],
|
'border-style': ['all'],
|
'basic-style-selector': ['colors', 'alpha'],
|
'label-selector': ['fontSize', 'color', 'showQuota', 'showProportion'],
|
'misc-selector': [
|
'liquidShape',
|
'liquidSize',
|
'liquidMaxType',
|
'liquidMaxField',
|
'liquidShowBorder',
|
'liquidBorderWidth',
|
'liquidBorderDistance'
|
],
|
'title-selector': [
|
'title',
|
'fontSize',
|
'color',
|
'hPosition',
|
'isItalic',
|
'isBolder',
|
'remarkShow',
|
'fontFamily',
|
'letterSpace',
|
'fontShadow'
|
],
|
threshold: ['liquidThreshold']
|
}
|
axis: AxisType[] = ['yAxis', 'filter']
|
axisConfig: AxisConfig = {
|
yAxis: {
|
name: `${t('chart.drag_block_progress')} / ${t('chart.quota')}`,
|
type: 'q',
|
limit: 1
|
}
|
}
|
|
async drawChart(drawOptions: G2PlotDrawOptions<G2Liquid>): Promise<G2Liquid> {
|
const { chart, container, action } = drawOptions
|
if (!chart.data?.series || !chart.yAxis.length) {
|
return
|
}
|
const initOptions: LiquidOptions = {
|
percent: 0
|
}
|
const options = this.setupOptions(chart, initOptions)
|
const { Liquid: G2Liquid } = await import('@antv/g2plot/esm/plots/liquid')
|
const newChart = new G2Liquid(container, options)
|
newChart.on('afterrender', () => {
|
action({
|
from: 'liquid',
|
data: {
|
type: 'liquid',
|
max: chart.data?.series[0]?.data[0]
|
}
|
})
|
})
|
// 处理空数据, 只要有一个指标是空数据,就不显示图表
|
const hasNoneData = chart.data?.series.some(
|
s => s.data?.[0] === undefined || s.data?.[0] === null
|
)
|
this.configEmptyDataStyle(hasNoneData ? [] : [1], container, newChart)
|
if (hasNoneData) {
|
return
|
}
|
return newChart
|
}
|
|
protected configTheme(chart: Chart, options: LiquidOptions): LiquidOptions {
|
const customAttr = parseJson(chart.customAttr)
|
const colors: string[] = []
|
if (customAttr.basicStyle) {
|
const basicStyle = customAttr.basicStyle
|
basicStyle.colors.forEach(ele => {
|
colors.push(hexColorToRGBA(ele, basicStyle.alpha))
|
})
|
}
|
const customStyle = parseJson(chart.customStyle)
|
let bgColor
|
if (customStyle.background) {
|
bgColor = hexColorToRGBA(customStyle.background.color, customStyle.background.alpha)
|
}
|
const theme = {
|
styleSheet: {
|
brandColor: colors[0],
|
paletteQualitative10: colors,
|
paletteQualitative20: colors,
|
backgroundColor: bgColor
|
}
|
}
|
return { ...options, theme }
|
}
|
|
protected configMisc(chart: Chart, options: LiquidOptions): LiquidOptions {
|
const customAttr = parseJson(chart.customAttr)
|
let value = 0
|
if (chart.data.series.length > 0) {
|
value = chart.data.series[0].data[0]
|
}
|
let max, radius, shape
|
if (customAttr.misc) {
|
const misc = customAttr.misc
|
const defaultLiquidMax = chart.data?.series[chart.data?.series.length - 1]?.data[0]
|
if (misc.liquidMaxType === 'dynamic') {
|
max = defaultLiquidMax
|
} else {
|
max = misc.liquidMax ? misc.liquidMax : defaultLiquidMax
|
}
|
radius = (misc.liquidSize ? misc.liquidSize : DEFAULT_MISC.liquidSize) / 100
|
shape = misc.liquidShape ?? DEFAULT_MISC.liquidShape
|
}
|
const size: LiquidOptions = {
|
percent: value / max,
|
radius: radius,
|
shape: shape
|
}
|
const { misc } = customAttr
|
if (misc?.liquidShowBorder) {
|
defaultsDeep(size, {
|
outline: {
|
border: misc.liquidBorderWidth ?? DEFAULT_MISC.liquidBorderWidth,
|
distance: misc.liquidBorderDistance ?? DEFAULT_MISC.liquidBorderDistance
|
}
|
})
|
}
|
return { ...options, ...size }
|
}
|
|
protected configLabel(chart: Chart, options: LiquidOptions): LiquidOptions {
|
const customAttr = parseJson(chart.customAttr)
|
const originVal = options.percent
|
// 数值过大图表会异常,大于 1 无意义
|
if (originVal > 1) {
|
options = {
|
...options,
|
percent: 1
|
}
|
}
|
if (!customAttr.label?.show) {
|
return {
|
...options,
|
statistic: {
|
content: false
|
}
|
}
|
}
|
const label = customAttr.label
|
const style = {
|
fontSize: label.fontSize.toString() + 'px',
|
color: label.color,
|
lineHeight: '"unset"',
|
overflow: 'visible',
|
opacity: 1
|
}
|
const title = label.showQuota
|
? {
|
style,
|
formatter: () => {
|
return valueFormatter(chart.data.series[0].data[0], label.quotaLabelFormatter)
|
}
|
}
|
: false
|
const content = label.showProportion
|
? {
|
style,
|
formatter: () => {
|
return (originVal * 100).toFixed(label.reserveDecimalCount) + '%'
|
}
|
}
|
: false
|
|
return {
|
...options,
|
statistic: {
|
title,
|
content
|
}
|
}
|
}
|
|
protected configThreshold(chart: Chart, options: LiquidOptions): LiquidOptions {
|
const senior = parseJson(chart.senior)
|
if (senior?.threshold?.enable) {
|
const { liquidThreshold } = senior?.threshold
|
if (liquidThreshold) {
|
const { paletteQualitative10: colors } = (options.theme as any).styleSheet
|
const liquidStyle = () => {
|
const thresholdArr = liquidThreshold.split(',')
|
let index = 0
|
thresholdArr.forEach((v, i) => {
|
if (options.percent > parseFloat(v) / 100) {
|
index = i + 1
|
}
|
})
|
return {
|
fill: colors[index % colors.length],
|
stroke: colors[index % colors.length]
|
}
|
}
|
return { ...options, liquidStyle }
|
}
|
}
|
return options
|
}
|
|
setupDefaultOptions(chart: ChartObj): ChartObj {
|
chart.customAttr.label = {
|
...chart.customAttr.label,
|
fontSize: 12,
|
show: true,
|
labelFormatter: {
|
type: 'percent',
|
thousandSeparator: true,
|
decimalCount: 2
|
}
|
}
|
return chart
|
}
|
|
protected setupOptions(chart: Chart, options: LiquidOptions): LiquidOptions {
|
return flow(
|
this.configTheme,
|
this.configMisc,
|
this.configLabel,
|
this.configThreshold
|
)(chart, options)
|
}
|
constructor() {
|
super('liquid', DEFAULT_LIQUID_DATA)
|
}
|
}
|