Feat: support data labels on charts

This commit is contained in:
Jianhui Zhao
2026-02-05 11:08:26 +08:00
committed by ulleo
parent beebe6ce2f
commit 245dab206c
7 changed files with 111 additions and 46 deletions
@@ -19,6 +19,7 @@ import icon_into_item_outlined from '@/assets/svg/icon_into-item_outlined.svg'
import icon_window_max_outlined from '@/assets/svg/icon_window-max_outlined.svg'
import icon_window_mini_outlined from '@/assets/svg/icon_window-mini_outlined.svg'
import icon_copy_outlined from '@/assets/svg/icon_copy_outlined.svg'
import ICON_STYLE from '@/assets/svg/icon_style-set_outlined.svg'
import { useI18n } from 'vue-i18n'
import SQLComponent from '@/views/chat/component/SQLComponent.vue'
import { useAssistantStore } from '@/stores/assistant'
@@ -211,6 +212,8 @@ function showSql() {
sqlShow.value = true
}
const showLabel = ref(false)
function addToDashboard() {
const recordeInfo = {
id: '1-1',
@@ -393,6 +396,27 @@ watch(
</el-tooltip>
</div>
<div class="chart-select-container">
<el-tooltip
v-if="currentChartType !== 'table'"
effect="dark"
:offset="8"
:content="showLabel ? t('chat.hide_label') : t('chat.show_label')"
placement="top"
>
<el-button
class="tool-btn"
:class="{ 'chart-active': showLabel }"
text
@click="showLabel = !showLabel"
>
<el-icon size="16">
<ICON_STYLE />
</el-icon>
</el-button>
</el-tooltip>
</div>
<div v-if="message?.record?.sql">
<el-tooltip effect="dark" :offset="8" :content="t('chat.show_sql')" placement="top">
<el-button class="tool-btn" text @click="showSql">
@@ -498,6 +522,7 @@ watch(
:message="message"
:data="data"
:loading-data="loadingData"
:show-label="showLabel"
/>
</div>
<div v-if="dataObject.limit" class="over-limit-hint">
@@ -17,6 +17,7 @@ export abstract class BaseChart {
_name: string = 'base-chart'
axis: Array<ChartAxis> = []
data: Array<ChartData> = []
showLabel: boolean = false
constructor(id: string, name: string) {
this.id = id
@@ -14,6 +14,7 @@ const params = withDefaults(
y?: Array<ChartAxis>
series?: Array<ChartAxis>
multiQuotaName?: string | undefined
showLabel?: boolean
}>(),
{
data: () => [],
@@ -22,6 +23,7 @@ const params = withDefaults(
y: () => [],
series: () => [],
multiQuotaName: undefined,
showLabel: false,
}
)
@@ -61,14 +63,21 @@ const axis = computed(() => {
let chartInstance: BaseChart | undefined
function renderChart() {
chartInstance = getChartInstance(params.type, chartId.value)
if (chartInstance) {
chartInstance.showLabel = params.showLabel
chartInstance.init(axis.value, params.data)
chartInstance.render()
}
}
watch(
() => params.showLabel,
() => {
renderChart()
}
)
function destroyChart() {
if (chartInstance) {
chartInstance.destroy()
@@ -11,6 +11,7 @@ const props = defineProps<{
message: ChatMessage
data: Array<{ [key: string]: any }>
loadingData?: boolean
showLabel?: boolean
}>()
const { t } = useI18n()
@@ -117,6 +118,7 @@ defineExpose({
:series="series"
:data="data"
:multi-quota-name="multiQuotaName"
:show-label="showLabel"
/>
<el-empty v-else :description="loadingData ? t('chat.loading_data') : t('chat.no_data')" />
</div>
@@ -119,7 +119,7 @@ export class Bar extends BaseG2Chart {
elementHighlight: { background: true, region: true },
tooltip: { series: series.length > 0, shared: true },
},
tooltip: (data) => {
tooltip: (data: any) => {
if (series.length > 0) {
return {
name: data[series[0].value],
@@ -129,6 +129,30 @@ export class Bar extends BaseG2Chart {
return { name: y[0].name, value: `${data[y[0].value]}${_data.isPercent ? '%' : ''}` }
}
},
labels: this.showLabel
? [
{
text: (data: any) => {
const value = data[y[0].value]
if (value === undefined || value === null) {
return ''
}
return `${value}${_data.isPercent ? '%' : ''}`
},
position: (data: any) => {
if (data[y[0].value] < 0) {
return 'left'
}
return 'right'
},
transform: [
{ type: 'contrastReverse' },
{ type: 'exceedAdjust' },
{ type: 'overlapHide' },
],
},
]
: [],
} as G2Spec
if (series.length > 0) {
@@ -110,7 +110,7 @@ export class Column extends BaseG2Chart {
elementHighlight: { background: true, region: true },
tooltip: { series: series.length > 0, shared: true },
},
tooltip: (data) => {
tooltip: (data: any) => {
if (series.length > 0) {
return {
name: data[series[0].value],
@@ -120,28 +120,30 @@ export class Column extends BaseG2Chart {
return { name: y[0].name, value: `${data[y[0].value]}${_data.isPercent ? '%' : ''}` }
}
},
// labels: [
// {
// text: (data: any) => {
// const value = data[y[0].value]
// if (value === undefined || value === null) {
// return ''
// }
// return `${value}${_data.isPercent ? '%' : ''}`
// },
// position: (data: any) => {
// if (data[y[0].value] < 0) {
// return 'bottom'
// }
// return 'top'
// },
// transform: [
// { type: 'contrastReverse' },
// { type: 'exceedAdjust' },
// { type: 'overlapHide' },
// ],
// },
// ],
labels: this.showLabel
? [
{
text: (data: any) => {
const value = data[y[0].value]
if (value === undefined || value === null) {
return ''
}
return `${value}${_data.isPercent ? '%' : ''}`
},
position: (data: any) => {
if (data[y[0].value] < 0) {
return 'bottom'
}
return 'top'
},
transform: [
{ type: 'contrastReverse' },
{ type: 'exceedAdjust' },
{ type: 'overlapHide' },
],
},
]
: [],
} as G2Spec
if (series.length > 0) {
@@ -86,27 +86,29 @@ export class Line extends BaseG2Chart {
encode: {
shape: 'smooth',
},
// labels: [
// {
// text: (data: any) => {
// const value = data[y[0].value]
// if (value === undefined || value === null) {
// return ''
// }
// return `${value}${_data.isPercent ? '%' : ''}`
// },
// style: {
// dx: -10,
// dy: -12,
// },
// transform: [
// { type: 'contrastReverse' },
// { type: 'exceedAdjust' },
// { type: 'overlapHide' },
// ],
// },
// ],
tooltip: (data) => {
labels: this.showLabel
? [
{
text: (data: any) => {
const value = data[y[0].value]
if (value === undefined || value === null) {
return ''
}
return `${value}${_data.isPercent ? '%' : ''}`
},
style: {
dx: -10,
dy: -12,
},
transform: [
{ type: 'contrastReverse' },
{ type: 'exceedAdjust' },
{ type: 'overlapHide' },
],
},
]
: [],
tooltip: (data: any) => {
if (series.length > 0) {
return {
name: data[series[0].value],