feat(图表): 折线图图例支持排序 #13256

This commit is contained in:
wisonic-s
2025-03-31 18:37:18 +08:00
committed by GitHub
parent aa0e252659
commit f57ae108dc
8 changed files with 180 additions and 19 deletions

View File

@@ -2075,7 +2075,8 @@ export default {
threshold_value: 'Threshold Value',
range_num: 'Number of Range',
show_range_bg: 'Show Range Background',
last_item: 'Last item'
last_item: 'Last item',
legend_sort: 'Legend sort'
},
dataset: {
field_value: 'Field Value',

View File

@@ -2018,7 +2018,8 @@ export default {
threshold_value: '分界值',
range_num: '區間背景個數',
show_range_bg: '顯示區間背景',
last_item: '最後一項'
last_item: '最後一項',
legend_sort: '圖例排序'
},
dataset: {
field_value: '欄位值',

View File

@@ -2024,7 +2024,8 @@ export default {
threshold_value: '分界值',
range_num: '区间背景个数',
show_range_bg: '显示区间背景',
last_item: '最后一项'
last_item: '最后一项',
legend_sort: '图例排序'
},
dataset: {
field_value: '字段值',
@@ -3324,7 +3325,6 @@ export default {
template: '模板',
category: '分类',
all_org: '所有组织',
custom: '自定义',
import_template: '导入模板',
copy_template: '复用模板',
upload_template: '上传模板',

View File

@@ -122,11 +122,22 @@ declare interface ChartLegendStyle {
* 字体大小
*/
fontSize: number
/**
* 图例大小
*/
size: number
/**
* 子弹图显示区间背景
*/
showRange: true
/**
* 排序方式
*/
sort: 'none' | 'asc' | 'desc' | 'custom'
/**
* 自定义排序
*/
customSort: string[]
}
/**

View File

@@ -24,6 +24,11 @@ const props = defineProps({
fieldType: {
type: String,
required: true
},
originSortList: {
type: Array,
default: () => [],
required: false
}
})
@@ -54,6 +59,17 @@ const init = () => {
reqMethod(param)
.then(response => {
const strArr = response.data
if (props.originSortList?.length) {
const tmp = []
props.originSortList.forEach(ele => {
const index = strArr.findIndex(item => item === ele)
if (index !== -1) {
tmp.push(strArr[index])
strArr.splice(index, 1)
}
})
strArr.unshift(...tmp)
}
state.sortList = strArr.map(ele => {
return transStr2Obj(ele)
})

View File

@@ -16,6 +16,7 @@ import { ElCol, ElFormItem, ElRow, ElSpace } from 'element-plus-secondary'
import { cloneDeep } from 'lodash-es'
import { useEmitt } from '@/hooks/web/useEmitt'
import { getDynamicColorScale } from '@/views/chart/components/js/util'
import CustomSortEdit from '@/views/chart/components/editor/drag-item/components/CustomSortEdit.vue'
const { t } = useI18n()
@@ -55,7 +56,9 @@ const state = reactive({
legendForm: {
...JSON.parse(JSON.stringify(DEFAULT_LEGEND_STYLE)),
miscForm: JSON.parse(JSON.stringify(DEFAULT_MISC)) as ChartMiscAttr
}
},
showCustomSort: false,
customSortField: null
})
const chartType = computed(() => {
@@ -226,6 +229,31 @@ const getMapCustomRange = index => {
if (index === state.legendForm.miscForm.mapLegendNumber) return t('chart.max')
return ''
}
const customSort = []
const changeLegendSort = sort => {
if (sort === 'custom') {
state.customSortField = cloneDeep(props.chart.xAxisExt?.[0])
if (!state.customSortField) {
return
}
state.showCustomSort = true
} else {
state.showCustomSort = false
state.legendForm.sort = sort
}
changeLegendStyle('sort')
}
const closeCustomSort = () => {
state.showCustomSort = false
}
const saveCustomSort = () => {
state.showCustomSort = false
state.legendForm.customSort = customSort
changeLegendStyle('customSort')
}
const customSortChange = list => {
customSort.splice(0, customSort.length, ...list)
}
onMounted(() => {
init()
})
@@ -674,7 +702,54 @@ onMounted(() => {
</el-radio-group>
</el-form-item>
</el-space>
<el-form-item
class="form-item"
v-if="showProperty('legendSort')"
:class="'form-item-' + themes"
:label="t('chart.legend_sort')"
>
<el-select
:effect="themes"
v-model="state.legendForm.sort"
size="small"
@change="changeLegendSort"
>
<el-option :label="t('chart.none')" value="none" />
<el-option :label="t('chart.asc')" value="asc" />
<el-option :label="t('chart.desc')" value="desc" />
<el-option
value="custom"
:disabled="!chart.xAxisExt?.length"
:label="t('visualization.custom_sort')"
@click="changeLegendSort('custom')"
/>
</el-select>
</el-form-item>
</el-form>
<el-dialog
v-if="state.showCustomSort"
v-model="state.showCustomSort"
:title="t('chart.custom_sort') + t('chart.sort')"
:visible="state.showCustomSort"
:close-on-click-modal="false"
destroy-on-close
width="372px"
class="dialog-css custom_sort_dialog"
>
<custom-sort-edit
field-type="xAxisExt"
:chart="chart"
:field="state.customSortField"
:origin-sort-list="state.legendForm.customSort"
@on-sort-change="customSortChange"
/>
<template #footer>
<div class="dialog-footer">
<el-button @click="closeCustomSort">{{ t('chart.cancel') }} </el-button>
<el-button type="primary" @click="saveCustomSort">{{ t('chart.confirm') }} </el-button>
</div>
</template>
</el-dialog>
</template>
<style lang="less" scoped>

View File

@@ -578,18 +578,6 @@ export const DEFAULT_TITLE_STYLE_DARK = {
remarkBackgroundColor: '#5A5C62'
}
export const DEFAULT_LEGEND_STYLE: ChartLegendStyle = {
show: true,
hPosition: 'center',
vPosition: 'bottom',
orient: 'horizontal',
icon: 'circle',
color: '#333333',
fontSize: 12,
size: 4,
showRange: true
}
export const DEFAULT_LEGEND_STYLE_BASE: ChartLegendStyle = {
show: true,
hPosition: 'center',
@@ -599,7 +587,23 @@ export const DEFAULT_LEGEND_STYLE_BASE: ChartLegendStyle = {
color: '#333333',
fontSize: 12,
size: 4,
showRange: true
showRange: true,
sort: 'none',
customSort: []
}
export const DEFAULT_LEGEND_STYLE: ChartLegendStyle = {
show: true,
hPosition: 'center',
vPosition: 'bottom',
orient: 'horizontal',
icon: 'circle',
color: '#333333',
fontSize: 12,
size: 4,
showRange: true,
sort: 'none',
customSort: []
}
export const DEFAULT_LEGEND_STYLE_LIGHT: ChartLegendStyle = {

View File

@@ -10,10 +10,12 @@ import {
TOOLTIP_TPL
} from '../../common/common_antv'
import {
convertToAlphaColor,
flow,
getLineConditions,
getLineLabelColorByCondition,
hexColorToRGBA,
isAlphaColor,
parseJson,
setUpGroupSeriesColor
} from '@/views/chart/components/js/util'
@@ -44,7 +46,8 @@ export class Line extends G2PlotChartView<LineOptions, G2Line> {
'tooltip-selector': [
...LINE_EDITOR_PROPERTY_INNER['tooltip-selector'],
'seriesTooltipFormatter'
]
],
'legend-selector': [...LINE_EDITOR_PROPERTY_INNER['legend-selector'], 'legendSort']
}
axis: AxisType[] = [...LINE_AXIS_TYPE, 'xAxisExt']
axisConfig = {
@@ -351,6 +354,56 @@ export class Line extends G2PlotChartView<LineOptions, G2Line> {
fill: style.stroke
}
}
const { sort, customSort, icon } = customStyle.legend
if (sort && sort !== 'none' && chart.xAxisExt.length) {
const customAttr = parseJson(chart.customAttr)
const { basicStyle } = customAttr
const seriesMap =
basicStyle.seriesColor?.reduce((p, n) => {
p[n.id] = n
return p
}, {}) || {}
const dupCheck = new Set()
const items = optionTmp.data?.reduce((arr, item) => {
if (!dupCheck.has(item.category)) {
const fill =
seriesMap[item.category]?.color ??
optionTmp.color[dupCheck.size % optionTmp.color.length]
dupCheck.add(item.category)
arr.push({
name: item.category,
value: item.category,
marker: {
symbol: icon,
style: {
r: size,
fill: isAlphaColor(fill) ? fill : convertToAlphaColor(fill, basicStyle.alpha)
}
}
})
}
return arr
}, [])
if (sort !== 'custom') {
items.sort((a, b) => {
return sort !== 'desc' ? a.name.localeCompare(b.name) : b.name.localeCompare(a.name)
})
} else {
const tmp = []
;(customSort || []).forEach(item => {
const index = items.findIndex(i => i.name === item)
if (index !== -1) {
tmp.push(items[index])
items.splice(index, 1)
}
})
items.unshift(...tmp)
}
optionTmp.legend.items = items
if (xAxisExt?.customSort?.length > 0) {
delete optionTmp.meta?.category.values
}
}
return optionTmp
}
protected setupOptions(chart: Chart, options: LineOptions): LineOptions {