mirror of
https://github.com/dataease/dataease.git
synced 2026-05-19 10:18:11 +08:00
feat(图表): 折线图图例支持排序 #13256
This commit is contained in:
@@ -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',
|
||||
|
||||
@@ -2018,7 +2018,8 @@ export default {
|
||||
threshold_value: '分界值',
|
||||
range_num: '區間背景個數',
|
||||
show_range_bg: '顯示區間背景',
|
||||
last_item: '最後一項'
|
||||
last_item: '最後一項',
|
||||
legend_sort: '圖例排序'
|
||||
},
|
||||
dataset: {
|
||||
field_value: '欄位值',
|
||||
|
||||
@@ -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: '上传模板',
|
||||
|
||||
@@ -122,11 +122,22 @@ declare interface ChartLegendStyle {
|
||||
* 字体大小
|
||||
*/
|
||||
fontSize: number
|
||||
/**
|
||||
* 图例大小
|
||||
*/
|
||||
size: number
|
||||
/**
|
||||
* 子弹图显示区间背景
|
||||
*/
|
||||
showRange: true
|
||||
/**
|
||||
* 排序方式
|
||||
*/
|
||||
sort: 'none' | 'asc' | 'desc' | 'custom'
|
||||
/**
|
||||
* 自定义排序
|
||||
*/
|
||||
customSort: string[]
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user