feat(图表): 仪表盘支持隐藏刻度标签和显示数值格式的标签 #9510

This commit is contained in:
wisonic-s 2024-05-29 15:06:26 +08:00
parent 18965a389e
commit 57935c4016
12 changed files with 137 additions and 55 deletions

View File

@ -1165,7 +1165,9 @@ export default {
top_n_input_2: ', 其余合并至其他',
top_n_label: '其他项名称',
progress_target: '目标值',
progress_current: '实际值'
progress_current: '实际值',
gauge_axis_label: '显示刻度',
gauge_percentage_tick: '百分比刻度'
},
dataset: {
scope_edit: '仅编辑时生效',

View File

@ -104,6 +104,14 @@ declare interface ChartBasicStyle {
* 仪表盘样式
*/
gaugeStyle: string
/**
* 仪表盘刻度显示
*/
gaugeAxisLine: boolean
/**
* 仪表盘百分比刻度
*/
gaugePercentLabel: boolean
/**
* 配色方案
*/

View File

@ -231,7 +231,12 @@ init()
<div @keydown.stop @keyup.stop style="width: 100%; margin-bottom: 16px">
<!--仪表盘-->
<el-col v-show="showProperty('gaugeThreshold')">
<el-form ref="thresholdForm" :model="state.thresholdForm" label-position="top">
<el-form
:model="state.thresholdForm"
ref="thresholdForm"
label-position="top"
@submit.prevent
>
<el-form-item
:label="t('chart.threshold_range') + '(%)'"
class="form-item"
@ -261,7 +266,12 @@ init()
</el-form>
</el-col>
<el-col v-show="showProperty('liquidThreshold')">
<el-form ref="thresholdForm" :model="state.thresholdForm" label-position="top">
<el-form
:model="state.thresholdForm"
ref="thresholdForm"
label-position="top"
@submit.prevent
>
<el-form-item
:label="t('chart.threshold_range') + '(%)'"
class="form-item"

View File

@ -777,6 +777,34 @@ onMounted(() => {
/>
</el-select>
</el-form-item>
<el-form-item
v-if="showProperty('gaugeAxisLine')"
class="form-item"
:class="'form-item-' + themes"
>
<el-checkbox
v-model="state.basicStyleForm.gaugeAxisLine"
:effect="themes"
size="small"
@change="changeBasicStyle('gaugeAxisLine')"
>
{{ t('chart.gauge_axis_label') }}</el-checkbox
>
</el-form-item>
<el-form-item
v-if="showProperty('gaugePercentLabel') && state.basicStyleForm.gaugeAxisLine"
class="form-item"
:class="'form-item-' + themes"
>
<el-checkbox
v-model="state.basicStyleForm.gaugePercentLabel"
:effect="themes"
size="small"
@change="changeBasicStyle('gaugePercentLabel')"
>
{{ t('chart.gauge_percentage_tick') }}</el-checkbox
>
</el-form-item>
<!--gauge end-->
<!--bar start-->
<el-form-item

View File

@ -3291,7 +3291,7 @@ span {
}
:deep(.ed-tabs__content) {
height: calc(100% - 33px);
height: calc(100% - 35px);
overflow-y: auto;
overflow-x: hidden;
}

View File

@ -1435,7 +1435,9 @@ export const DEFAULT_BASIC_STYLE: ChartBasicStyle = {
tableLayoutMode: 'grid',
calcTopN: false,
topN: 5,
topNLabel: '其他'
topNLabel: '其他',
gaugeAxisLine: true,
gaugePercentLabel: true
}
export const BASE_VIEW_CONFIG = {

View File

@ -95,7 +95,8 @@ export class BubbleMap extends L7PlotChartView<ChoroplethOptions, Choropleth> {
// 禁用线上地图数据
customFetchGeoData: () => null
}
options = this.setupOptions(chart, options, drawOption, geoJson)
const context = { drawOption, geoJson }
options = this.setupOptions(chart, options, context)
const view = new Choropleth(container, options)
const dotLayer = this.getDotLayer(chart, geoJson, drawOption)
this.configZoomButton(chart, view)
@ -170,10 +171,10 @@ export class BubbleMap extends L7PlotChartView<ChoroplethOptions, Choropleth> {
private configBasicStyle(
chart: Chart,
options: ChoroplethOptions,
extra: any[]
context: Record<string, any>
): ChoroplethOptions {
const { areaId }: L7PlotDrawOptions<any> = extra[0]
const geoJson: FeatureCollection = extra[1]
const { areaId }: L7PlotDrawOptions<any> = context.drawOption
const geoJson: FeatureCollection = context.geoJson
const { basicStyle, label } = parseJson(chart.customAttr)
const senior = parseJson(chart.senior)
const curAreaNameMapping = senior.areaMapping?.[areaId]
@ -208,7 +209,7 @@ export class BubbleMap extends L7PlotChartView<ChoroplethOptions, Choropleth> {
protected setupOptions(
chart: Chart,
options: ChoroplethOptions,
...extra: any[]
context: Record<string, any>
): ChoroplethOptions {
return flow(
this.configEmptyDataStrategy,
@ -216,6 +217,6 @@ export class BubbleMap extends L7PlotChartView<ChoroplethOptions, Choropleth> {
this.configStyle,
this.configTooltip,
this.configBasicStyle
)(chart, options, extra)
)(chart, options, context)
}
}

View File

@ -96,7 +96,8 @@ export class Map extends L7PlotChartView<ChoroplethOptions, Choropleth> {
// 禁用线上地图数据
customFetchGeoData: () => null
}
options = this.setupOptions(chart, options, drawOption, geoJson)
const context = { drawOption, geoJson }
options = this.setupOptions(chart, options, context)
const view = new Choropleth(container, options)
this.configZoomButton(chart, view)
view.once('loaded', () => {
@ -120,10 +121,10 @@ export class Map extends L7PlotChartView<ChoroplethOptions, Choropleth> {
private configBasicStyle(
chart: Chart,
options: ChoroplethOptions,
extra: any[]
context: Record<string, any>
): ChoroplethOptions {
const { areaId }: L7PlotDrawOptions<any> = extra[0]
const geoJson: FeatureCollection = extra[1]
const { areaId }: L7PlotDrawOptions<any> = context.drawOption
const geoJson: FeatureCollection = context.geoJson
const { basicStyle, label } = parseJson(chart.customAttr)
const senior = parseJson(chart.senior)
const curAreaNameMapping = senior.areaMapping?.[areaId]
@ -176,7 +177,7 @@ export class Map extends L7PlotChartView<ChoroplethOptions, Choropleth> {
protected setupOptions(
chart: Chart,
options: ChoroplethOptions,
...extra: any[]
context: Record<string, any>
): ChoroplethOptions {
return flow(
this.configEmptyDataStrategy,
@ -185,6 +186,6 @@ export class Map extends L7PlotChartView<ChoroplethOptions, Choropleth> {
this.configTooltip,
this.configBasicStyle,
this.configLegend
)(chart, options, extra)
)(chart, options, context)
}
}

View File

@ -13,6 +13,7 @@ import {
import { valueFormatter } from '@/views/chart/components/js/formatter'
import { getPadding, setGradientColor } from '@/views/chart/components/js/panel/common/common_antv'
import { useI18n } from '@/hooks/web/useI18n'
import { merge } from 'lodash-es'
const { t } = useI18n()
@ -28,7 +29,7 @@ export class Gauge extends G2PlotChartView<GaugeOptions, G2Gauge> {
]
propertyInner: EditorPropertyInner = {
'background-overall-component': ['all'],
'basic-style-selector': ['colors', 'alpha', 'gaugeStyle', 'gradient'],
'basic-style-selector': ['colors', 'alpha', 'gradient', 'gaugeAxisLine', 'gaugePercentLabel'],
'label-selector': ['fontSize', 'color', 'labelFormatter'],
'title-selector': [
'title',
@ -77,10 +78,6 @@ export class Gauge extends G2PlotChartView<GaugeOptions, G2Gauge> {
label: {
style: {
fontSize: getScaleValue(12, scale) // 刻度值字体大小
},
formatter: function (v) {
const r = parseFloat(v)
return v === '0' || !r ? v : r * 100 + '%'
}
},
tickLine: {
@ -98,11 +95,15 @@ export class Gauge extends G2PlotChartView<GaugeOptions, G2Gauge> {
}
}
}
const options = this.setupOptions(chart, initOptions, scale)
const options = this.setupOptions(chart, initOptions, { scale })
return new G2Gauge(container, options)
}
protected configMisc(chart: Chart, options: GaugeOptions): GaugeOptions {
protected configMisc(
chart: Chart,
options: GaugeOptions,
context: Record<string, any>
): GaugeOptions {
const customAttr = parseJson(chart.customAttr)
const data = chart.data.series[0].data[0]
let min, max, startAngle, endAngle
@ -123,6 +124,8 @@ export class Gauge extends G2PlotChartView<GaugeOptions, G2Gauge> {
}
startAngle = (misc.gaugeStartAngle * Math.PI) / 180
endAngle = (misc.gaugeEndAngle * Math.PI) / 180
context.min = min
context.max = max
}
const percent = (parseFloat(data) - parseFloat(min)) / (parseFloat(max) - parseFloat(min))
const tmp = {
@ -133,8 +136,12 @@ export class Gauge extends G2PlotChartView<GaugeOptions, G2Gauge> {
return { ...options, ...tmp }
}
private configRange(chart: Chart, options: GaugeOptions, extra: any[]): GaugeOptions {
const [scale] = extra
private configRange(
chart: Chart,
options: GaugeOptions,
context: Record<string, any>
): GaugeOptions {
const { scale } = context
const range = [0]
let index = 0
let flag = false
@ -216,36 +223,55 @@ export class Gauge extends G2PlotChartView<GaugeOptions, G2Gauge> {
return { ...options, ...rangOptions }
}
protected configLabel(chart: Chart, options: GaugeOptions): GaugeOptions {
protected configLabel(
chart: Chart,
options: GaugeOptions,
context?: Record<string, any>
): GaugeOptions {
const customAttr = parseJson(chart.customAttr)
const data = chart.data.series[0].data[0]
let labelContent
if (customAttr.label) {
const label = customAttr.label
const labelFormatter = label.labelFormatter ?? DEFAULT_LABEL.labelFormatter
if (label.show) {
labelContent = {
style: () => ({
fontSize: label.fontSize,
color: label.color
}),
formatter: function () {
let value
if (labelFormatter.type === 'percent') {
value = options.percent
} else {
value = data
}
return valueFormatter(value, labelFormatter)
let labelContent: GaugeOptions['statistic']['content'] = false
const label = customAttr.label
const labelFormatter = label.labelFormatter ?? DEFAULT_LABEL.labelFormatter
if (label.show) {
labelContent = {
style: {
fontSize: `${label.fontSize}`,
color: label.color
},
formatter: function () {
let value
if (labelFormatter.type === 'percent') {
value = options.percent
} else {
value = data
}
return valueFormatter(value, labelFormatter)
}
} else {
labelContent = false
}
} as GaugeOptions['statistic']['content']
}
const statistic = {
content: labelContent
}
const { gaugeAxisLine, gaugePercentLabel } = customAttr.basicStyle
const { min, max } = context
const tmp = {
axis: {
label: {
formatter: v => {
if (gaugeAxisLine === false) {
return ''
}
if (gaugePercentLabel === false) {
const val = v === '0' ? min : v === '1' ? max : min + (max - min) * v
return valueFormatter(val, labelFormatter)
}
return v === '0' ? v : v * 100 + '%'
}
}
}
}
options = merge(options, tmp)
return { ...options, statistic }
}
@ -263,13 +289,17 @@ export class Gauge extends G2PlotChartView<GaugeOptions, G2Gauge> {
return chart
}
protected setupOptions(chart: Chart, options: GaugeOptions, ...extra: any[]): GaugeOptions {
protected setupOptions(
chart: Chart,
options: GaugeOptions,
context: Record<string, any>
): GaugeOptions {
return flow(
this.configTheme,
this.configMisc,
this.configLabel,
this.configRange
)(chart, options, extra)
)(chart, options, context)
}
constructor() {
super('gauge', DEFAULT_DATA)

View File

@ -139,7 +139,7 @@ export abstract class G2PlotChartView<
* @param chart 数据库图表对象
* @param options 各个图表的参数泛化的 Options可以自行扩展比如加个扩展 X 轴或者扩展 Y 轴字段
*/
protected abstract setupOptions(chart: Chart, options: O): O
protected abstract setupOptions(chart: Chart, options: O, context?: Record<string, any>): O
protected constructor(name: string, defaultData: any[]) {
super(ChartLibraryType.G2_PLOT, name, defaultData)
}

View File

@ -81,5 +81,5 @@ export abstract class L7PlotChartView<
super(ChartLibraryType.L7_PLOT, name)
this.defaultData = defaultData
}
protected abstract setupOptions(chart: Chart, options: O): O
protected abstract setupOptions(chart: Chart, options: O, context?: Record<string, any>): O
}

View File

@ -388,12 +388,12 @@ export function parseJson<T>(str: T | JSONString<T>): T {
return JSON.parse(str) as T
}
type FlowFunction<P, R> = (param: P, result: R, extra?: any[]) => R
type FlowFunction<P, R> = (param: P, result: R, context?: Record<string, any>) => R
export function flow<P, R>(...flows: FlowFunction<P, R>[]): FlowFunction<P, R> {
return (param: P, result: R, extra?: any[]) => {
return (param: P, result: R, context?: Record<string, any>) => {
return flows.reduce((result: R, flow: FlowFunction<P, R>) => {
return flow(param, result, extra)
return flow(param, result, context)
}, result)
}
}