mirror of
https://github.com/dataease/dataease.git
synced 2026-06-16 11:21:44 +08:00
Merge remote-tracking branch 'origin/dev-v3' into dev-v3
This commit is contained in:
@@ -206,6 +206,9 @@ const showSort = computed(() => {
|
||||
return !isChartMix || isDimensionType
|
||||
})
|
||||
const showSortPriority = computed(() => {
|
||||
if (props.chart.type === 'line' && props.type === 'dimensionExt') {
|
||||
return false
|
||||
}
|
||||
if (props.chart.type.includes('chart-mix')) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@ const getRgbaColorLastRgba = (rgbaString: string) => {
|
||||
return lastRGBA
|
||||
}
|
||||
|
||||
const EXTREMUM_LABEL_MARK_TYPES = ['point', 'interval']
|
||||
|
||||
/**
|
||||
* 判断图表类型是否支持最值标注(极值标签)
|
||||
* @param chart - 图表配置对象
|
||||
@@ -94,7 +96,7 @@ export const extremumEvt = (
|
||||
const chartData = options.children ? options.children : [options]
|
||||
// 遍历所有 series,为标签注入 HTML 和样式
|
||||
chartData
|
||||
.filter(item => item.labels?.length)
|
||||
.filter(item => item.labels?.length && EXTREMUM_LABEL_MARK_TYPES.includes(item.type))
|
||||
.forEach(item => {
|
||||
item.labels.forEach(label => {
|
||||
const oldPosition = label.position || 'top'
|
||||
|
||||
@@ -75,7 +75,7 @@ export class StackBar extends Bar {
|
||||
fill: labelAttr.color,
|
||||
fontSize: labelAttr.fontSize,
|
||||
...position,
|
||||
formatter: (value, _data) => valueFormatter(value, labelAttr.labelFormatter),
|
||||
formatter: value => valueFormatter(value, labelAttr.labelFormatter),
|
||||
...transform
|
||||
})
|
||||
}
|
||||
@@ -83,19 +83,38 @@ export class StackBar extends Bar {
|
||||
if (labelAttr.showTotal) {
|
||||
const formatterCfg = labelAttr.labelFormatter ?? formatterItem
|
||||
const groupedData = groupBy(options.data, 'field')
|
||||
for (const [key, values] of Object.entries(groupedData)) {
|
||||
const totalData = Object.entries(groupedData).map(([key, values]) => {
|
||||
const total = values.reduce((a, b) => a + b.value, 0)
|
||||
const value = valueFormatter(total, formatterCfg)
|
||||
return {
|
||||
field: key,
|
||||
value: total,
|
||||
totalLabel: valueFormatter(total, formatterCfg)
|
||||
}
|
||||
})
|
||||
if (totalData.length) {
|
||||
children.push({
|
||||
type: 'text',
|
||||
data: [key, total],
|
||||
style: {
|
||||
text: value,
|
||||
textAlign: 'center',
|
||||
dy: -10,
|
||||
fill: labelAttr.color,
|
||||
fontSize: labelAttr.fontSize
|
||||
type: 'point',
|
||||
data: totalData,
|
||||
encode: {
|
||||
x: 'field',
|
||||
y: 'value'
|
||||
},
|
||||
style: {
|
||||
opacity: 0
|
||||
},
|
||||
labels: [
|
||||
{
|
||||
text: 'totalLabel',
|
||||
fillOpacity: 1,
|
||||
fill: labelAttr.color,
|
||||
fontSize: labelAttr.fontSize,
|
||||
position: 'top',
|
||||
dx: 0,
|
||||
dy: -10,
|
||||
...transform,
|
||||
textAlign: 'center'
|
||||
}
|
||||
],
|
||||
tooltip: false
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { BAR_EDITOR_PROPERTY } from '@/views/chart/components/js/panel/charts/g2/bar/common'
|
||||
import {
|
||||
BAR_EDITOR_PROPERTY,
|
||||
BAR_EDITOR_PROPERTY_INNER
|
||||
} from '@/views/chart/components/js/panel/charts/g2/bar/common'
|
||||
import { flow, parseJson } from '@/views/chart/components/js/util'
|
||||
import {
|
||||
createTooltipWrapper,
|
||||
@@ -11,9 +14,9 @@ import {
|
||||
TOOLTIP_ITEM_TPL,
|
||||
TOOLTIP_TITLE_TPL
|
||||
} from '@/views/chart/components/js/panel/common/common_antv'
|
||||
import { valueFormatter } from '@/views/chart/components/js/formatter'
|
||||
import { formatterItem, valueFormatter } from '@/views/chart/components/js/formatter'
|
||||
import { HorizontalBar } from '@/views/chart/components/js/panel/charts/g2/bar/horizontal-bar'
|
||||
import { isEmpty } from 'lodash-es'
|
||||
import { groupBy, isEmpty } from 'lodash-es'
|
||||
|
||||
const { t } = useI18n()
|
||||
|
||||
@@ -33,7 +36,15 @@ export class HorizontalStackBar extends HorizontalBar {
|
||||
}
|
||||
propertyInner = {
|
||||
...this['propertyInner'],
|
||||
'label-selector': ['color', 'fontSize', 'hPosition', 'labelFormatter'],
|
||||
'label-selector': [
|
||||
...BAR_EDITOR_PROPERTY_INNER['label-selector'],
|
||||
'hPosition',
|
||||
'showTotal',
|
||||
'totalColor',
|
||||
'totalFontSize',
|
||||
'totalFormatter',
|
||||
'showStackQuota'
|
||||
],
|
||||
'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'tooltipFormatter', 'show']
|
||||
}
|
||||
|
||||
@@ -53,23 +64,64 @@ export class HorizontalStackBar extends HorizontalBar {
|
||||
...(labelAttr.fullDisplay ? [] : [{ type: 'overlapHide' }])
|
||||
]
|
||||
|
||||
const labels = [
|
||||
{
|
||||
const labels = []
|
||||
if (labelAttr.showStackQuota ?? true) {
|
||||
labels.push({
|
||||
text: 'value',
|
||||
fillOpacity: 1,
|
||||
fill: labelAttr.color,
|
||||
fontSize: labelAttr.fontSize,
|
||||
...position,
|
||||
formatter: (value, _data) => {
|
||||
debugger
|
||||
formatter: value => {
|
||||
if (value === null || value === undefined) {
|
||||
return ''
|
||||
}
|
||||
return valueFormatter(value, labelAttr.labelFormatter)
|
||||
},
|
||||
transform
|
||||
})
|
||||
}
|
||||
|
||||
if (labelAttr.showTotal) {
|
||||
const formatterCfg = labelAttr.labelFormatter ?? formatterItem
|
||||
const groupedData = groupBy(options.data, 'field')
|
||||
const totalData = Object.entries(groupedData).map(([key, values]) => {
|
||||
const total = values.reduce((a, b) => a + b.value, 0)
|
||||
return {
|
||||
field: key,
|
||||
value: total,
|
||||
totalLabel: valueFormatter(total, formatterCfg)
|
||||
}
|
||||
})
|
||||
if (totalData.length) {
|
||||
children.push({
|
||||
type: 'point',
|
||||
data: totalData,
|
||||
encode: {
|
||||
x: 'field',
|
||||
y: 'value'
|
||||
},
|
||||
coordinate: { transform: [{ type: 'transpose' }] },
|
||||
style: {
|
||||
opacity: 0
|
||||
},
|
||||
labels: [
|
||||
{
|
||||
text: 'totalLabel',
|
||||
fillOpacity: 1,
|
||||
fill: labelAttr.color,
|
||||
fontSize: labelAttr.fontSize,
|
||||
position: 'right',
|
||||
dx: 4,
|
||||
dy: 0,
|
||||
transform,
|
||||
textAlign: 'start'
|
||||
}
|
||||
],
|
||||
tooltip: false
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
return {
|
||||
...options,
|
||||
|
||||
@@ -15,7 +15,14 @@ import {
|
||||
} from '@/views/chart/components/js/util'
|
||||
import { cloneDeep, defaultsDeep, isEmpty, merge } from 'lodash-es'
|
||||
import { valueFormatter } from '@/views/chart/components/js/formatter'
|
||||
import { LINE_AXIS_TYPE, LINE_EDITOR_PROPERTY, LINE_EDITOR_PROPERTY_INNER } from './common'
|
||||
import {
|
||||
configStackOrderByYAxis,
|
||||
configYAxisSeriesLegendDomain,
|
||||
LINE_AXIS_TYPE,
|
||||
LINE_EDITOR_PROPERTY,
|
||||
LINE_EDITOR_PROPERTY_INNER,
|
||||
sortTooltipItemsByYAxis
|
||||
} from './common'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { addExtremumText, extremumEvt } from '@/views/chart/components/js/extremumUitl'
|
||||
import { Chart as G2Chart, G2Spec } from '@antv/g2'
|
||||
@@ -383,6 +390,7 @@ export class Area extends G2ChartView {
|
||||
lineLineDash,
|
||||
label: xAxis.axisLabel.show,
|
||||
labelFill: xAxis.axisLabel.color,
|
||||
labelOpacity: 1,
|
||||
labelFillOpacity: 1,
|
||||
labelFontSize: xAxis.axisLabel.fontSize,
|
||||
tick: xAxis.axisLabel.show,
|
||||
@@ -436,6 +444,7 @@ export class Area extends G2ChartView {
|
||||
lineLineDash,
|
||||
label: yAxis.axisLabel.show,
|
||||
labelFill: yAxis.axisLabel.color,
|
||||
labelOpacity: 1,
|
||||
labelFillOpacity: 1,
|
||||
labelFontSize: yAxis.axisLabel.fontSize,
|
||||
tick: false,
|
||||
@@ -501,7 +510,7 @@ export class Area extends G2ChartView {
|
||||
}
|
||||
}
|
||||
defaultsDeep(options, tmpLegend)
|
||||
return options
|
||||
return configYAxisSeriesLegendDomain(chart, options)
|
||||
}
|
||||
|
||||
protected configAssistLine(chart: Chart, options: G2Spec): G2Spec {
|
||||
@@ -616,7 +625,7 @@ export class Area extends G2ChartView {
|
||||
}
|
||||
const result = []
|
||||
const head = originalItems[0]
|
||||
tooltipItems.forEach(item => {
|
||||
sortTooltipItemsByYAxis(chart, tooltipItems).forEach(item => {
|
||||
if (item.value === null || item.value === undefined) {
|
||||
return
|
||||
}
|
||||
@@ -855,6 +864,10 @@ export class StackArea extends Area {
|
||||
return options
|
||||
}
|
||||
|
||||
protected configLegend(chart: Chart, options: G2Spec): G2Spec {
|
||||
return super.configLegend(chart, configStackOrderByYAxis(chart, options))
|
||||
}
|
||||
|
||||
protected configTooltip(chart: Chart, options: G2Spec): G2Spec {
|
||||
const customAttr: DeepPartial<ChartAttr> = parseJson(chart.customAttr)
|
||||
const tooltipAttr = customAttr.tooltip
|
||||
@@ -874,7 +887,7 @@ export class StackArea extends Area {
|
||||
render: (e, { title, items }) => {
|
||||
const titleHtml = TOOLTIP_TITLE_TPL.replace('{title}', title)
|
||||
const result = []
|
||||
items.forEach(item => {
|
||||
sortTooltipItemsByYAxis(chart, items).forEach(item => {
|
||||
if (item.value === null || item.value === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import type { G2Spec } from '@antv/g2'
|
||||
|
||||
export const LINE_EDITOR_PROPERTY: EditorProperty[] = [
|
||||
'background-overall-component',
|
||||
'border-style',
|
||||
@@ -72,3 +74,125 @@ export const LINE_AXIS_TYPE: AxisType[] = [
|
||||
'extLabel',
|
||||
'extTooltip'
|
||||
]
|
||||
|
||||
const Y_AXIS_SERIES_ORDER_NOT_FOUND = Number.MAX_SAFE_INTEGER
|
||||
|
||||
/**
|
||||
* 只有系列来自值轴指标时才按指标顺序处理;有分组/堆叠维度时,系列来自维度值,保留原逻辑
|
||||
*/
|
||||
export const isYAxisSeriesChart = (chart: Chart) => {
|
||||
return !!chart.yAxis?.length && !chart.xAxisExt?.length && !chart.extStack?.length
|
||||
}
|
||||
|
||||
/**
|
||||
* 指标系列在图表数据里的名称来自字段展示名,未设置展示名时使用字段名
|
||||
*/
|
||||
export const getYAxisSeriesName = axis => axis.chartShowName || axis.name
|
||||
|
||||
/**
|
||||
* 为 legend 生成值轴指标顺序的 color domain,同时保留数据里未匹配到的新系列
|
||||
*/
|
||||
export const getYAxisSeriesDomain = (chart: Chart, data: any[] = []) => {
|
||||
const domain = []
|
||||
chart.yAxis?.forEach(axis => {
|
||||
const name = getYAxisSeriesName(axis)
|
||||
if (name && !domain.includes(name)) {
|
||||
domain.push(name)
|
||||
}
|
||||
})
|
||||
data.forEach(item => {
|
||||
if (item.category && !domain.includes(item.category)) {
|
||||
domain.push(item.category)
|
||||
}
|
||||
})
|
||||
return domain
|
||||
}
|
||||
|
||||
/**
|
||||
* 建立指标 id/显示名到字段下标的映射,供 tooltip 和堆叠层级排序复用
|
||||
*/
|
||||
export const getYAxisOrderMap = (chart: Chart) => {
|
||||
const orderMap = new Map<string, number>()
|
||||
chart.yAxis?.forEach((axis, index) => {
|
||||
orderMap.set(axis.id, index)
|
||||
const name = getYAxisSeriesName(axis)
|
||||
if (name) {
|
||||
orderMap.set(name, index)
|
||||
}
|
||||
})
|
||||
return orderMap
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据指标字段顺序获取当前系列排序值,未命中时放到最后并保持原相对顺序
|
||||
*/
|
||||
export const getYAxisSeriesOrder = (orderMap: Map<string, number>, item) => {
|
||||
return (
|
||||
orderMap.get(item.quotaList?.[0]?.id) ??
|
||||
orderMap.get(item.category) ??
|
||||
Y_AXIS_SERIES_ORDER_NOT_FOUND
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 对 tooltip items 按右侧指标字段自上而下排序
|
||||
*/
|
||||
export const sortTooltipItemsByYAxis = (chart: Chart, items: any[]) => {
|
||||
if (!isYAxisSeriesChart(chart)) {
|
||||
return items
|
||||
}
|
||||
const orderMap = getYAxisOrderMap(chart)
|
||||
return items
|
||||
.map((item, index) => ({
|
||||
item,
|
||||
index,
|
||||
order: getYAxisSeriesOrder(orderMap, item)
|
||||
}))
|
||||
.sort((a, b) => a.order - b.order || a.index - b.index)
|
||||
.map(({ item }) => item)
|
||||
}
|
||||
|
||||
/**
|
||||
* 对 legend 的 color domain 按右侧指标字段自上而下排序,不覆盖已有颜色映射等样式配置
|
||||
*/
|
||||
export const configYAxisSeriesLegendDomain = (chart: Chart, options: G2Spec) => {
|
||||
if (!isYAxisSeriesChart(chart)) {
|
||||
return options
|
||||
}
|
||||
const domain = getYAxisSeriesDomain(chart, options.data?.value)
|
||||
if (!domain.length) {
|
||||
return options
|
||||
}
|
||||
const scale = options.scale ?? {}
|
||||
options.scale = {
|
||||
...scale,
|
||||
color: {
|
||||
...(scale.color ?? {}),
|
||||
domain
|
||||
}
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
/**
|
||||
* G2 正值堆叠是从下往上累加,堆叠折线需要反向使用指标下标来实现视觉自上而下对齐
|
||||
*/
|
||||
export const configStackOrderByYAxis = (chart: Chart, options: G2Spec) => {
|
||||
if (!isYAxisSeriesChart(chart)) {
|
||||
return options
|
||||
}
|
||||
const orderMap = getYAxisOrderMap(chart)
|
||||
options.transform = (options.transform ?? []).map(transform => {
|
||||
if (transform.type !== 'stackY') {
|
||||
return transform
|
||||
}
|
||||
return {
|
||||
...transform,
|
||||
orderBy: item => {
|
||||
const order = getYAxisSeriesOrder(orderMap, item)
|
||||
return order === Y_AXIS_SERIES_ORDER_NOT_FOUND ? order : -order
|
||||
}
|
||||
}
|
||||
})
|
||||
return options
|
||||
}
|
||||
|
||||
@@ -14,7 +14,13 @@ import {
|
||||
} from '@/views/chart/components/js/util'
|
||||
import { cloneDeep, defaultsDeep, isEmpty, merge } from 'lodash-es'
|
||||
import { valueFormatter } from '@/views/chart/components/js/formatter'
|
||||
import { LINE_AXIS_TYPE, LINE_EDITOR_PROPERTY, LINE_EDITOR_PROPERTY_INNER } from './common'
|
||||
import {
|
||||
configYAxisSeriesLegendDomain,
|
||||
LINE_AXIS_TYPE,
|
||||
LINE_EDITOR_PROPERTY,
|
||||
LINE_EDITOR_PROPERTY_INNER,
|
||||
sortTooltipItemsByYAxis
|
||||
} from './common'
|
||||
import { useI18n } from '@/hooks/web/useI18n'
|
||||
import { Chart as G2Chart, G2Spec } from '@antv/g2'
|
||||
import { DEFAULT_YAXIS_STYLE } from '@/views/chart/components/editor/util/chart'
|
||||
@@ -368,6 +374,7 @@ export class Line extends G2ChartView {
|
||||
lineLineDash,
|
||||
label: xAxis.axisLabel.show,
|
||||
labelFill: xAxis.axisLabel.color,
|
||||
labelOpacity: 1,
|
||||
labelFillOpacity: 1,
|
||||
labelFontSize: xAxis.axisLabel.fontSize,
|
||||
grid: xAxis.splitLine.show,
|
||||
@@ -420,6 +427,7 @@ export class Line extends G2ChartView {
|
||||
lineLineDash,
|
||||
label: yAxis.axisLabel.show,
|
||||
labelFill: yAxis.axisLabel.color,
|
||||
labelOpacity: 1,
|
||||
labelFillOpacity: 1,
|
||||
labelFontSize: yAxis.axisLabel.fontSize,
|
||||
grid: yAxis.splitLine.show,
|
||||
@@ -566,7 +574,7 @@ export class Line extends G2ChartView {
|
||||
defaultsDeep(options, scaleOpt)
|
||||
}
|
||||
}
|
||||
return options
|
||||
return configYAxisSeriesLegendDomain(chart, options)
|
||||
}
|
||||
|
||||
protected configAssistLine(chart: Chart, options: G2Spec): G2Spec {
|
||||
@@ -683,7 +691,7 @@ export class Line extends G2ChartView {
|
||||
}
|
||||
const result = []
|
||||
const head = originalItems[0]
|
||||
tooltipItems.forEach(item => {
|
||||
sortTooltipItemsByYAxis(chart, tooltipItems).forEach(item => {
|
||||
if (item.value === null || item.value === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user