feat: 新增饼图配制

This commit is contained in:
奔跑的面条 2025-06-15 16:36:31 +08:00
parent b3a8c23a47
commit cfb2a667bd
18 changed files with 228 additions and 141 deletions

View File

@ -197,7 +197,7 @@ const createOrUpdateChart = (
}
) => {
if (vChartRef.value && !chart) {
const spec = transformHandler[chartProps.category](chartProps)
const spec = transformHandler[chartProps.category || '']?.(chartProps)
chart = new VChart(
{ ...spec, data: chartProps.dataset },
{
@ -208,7 +208,7 @@ const createOrUpdateChart = (
chart.renderSync()
return true
} else if (chart) {
const spec = transformHandler[chartProps.category](chartProps)
const spec = transformHandler[chartProps.category || '']?.(chartProps)
chart.updateSpec({ ...spec, data: toRaw(chartProps.dataset), dataset: undefined })
return true
}

View File

@ -1,15 +1,10 @@
import { Datum } from "@visactor/vchart/esm/typings"
import { cloneDeep } from "lodash"
const INNER_RADIUS = 0.75
const OUTER_RADIUS = 0.68
import { Datum } from '@visactor/vchart/esm/typings'
import { cloneDeep } from 'lodash'
export default (chartProps: any) => {
const spec = cloneDeep(chartProps)
delete spec.category
spec.innerRadius = INNER_RADIUS
spec.outerRadius = OUTER_RADIUS
// tooltip
const keyFill = spec.tooltip.style.keyLabel.fill
const valueFill = spec.tooltip.style.valueLabel.fill
@ -21,119 +16,117 @@ export default (chartProps: any) => {
spec.tooltip.style.valueLabel.fontColor = valueFill
spec.tooltip.style.titleLabel.fontColor = titleFill
// extensionMark
spec.extensionMark = [
{
name: 'arc_inner_shadow',
type: 'arc',
dataId: 'id0',
style: {
interactive: false,
startAngle: (datum: Datum) => {
console.log('startAngle', datum)
return datum['__VCHART_ARC_START_ANGLE'];
},
endAngle: (datum: Datum) => {
return datum['__VCHART_ARC_END_ANGLE'];
},
innerRadius: (datum: Datum, context: any) => {
return context.getLayoutRadius() * spec.innerRadius - 30;
},
outerRadius: (datum: Datum, context: any) => {
return context.getLayoutRadius() * spec.innerRadius;
},
fillOpacity: 0.3,
fill: (datum: Datum, context: any) => {
console.log('context', context.seriesColor(datum[spec.seriesField]))
return context.seriesColor(datum[spec.seriesField]);
},
visible: true,
x: (datum: Datum, context: any) => {
return context.getCenter().x();
},
y: (datum: Datum, context: any) => {
return context.getCenter().y();
if (spec.extensionMark) {
// extensionMark
spec.extensionMark = [
{
name: 'arc_inner_shadow',
type: 'arc',
dataId: 'id0',
style: {
interactive: false,
startAngle: (datum: Datum) => {
return datum['__VCHART_ARC_START_ANGLE']
},
endAngle: (datum: Datum) => {
return datum['__VCHART_ARC_END_ANGLE']
},
innerRadius: (datum: Datum, context: any) => {
return context.getLayoutRadius() * spec.innerRadius - 30
},
outerRadius: (datum: Datum, context: any) => {
return context.getLayoutRadius() * spec.innerRadius
},
fillOpacity: 0.3,
fill: (datum: Datum, context: any) => {
return context.seriesColor(datum[spec.seriesField])
},
visible: true,
x: (datum: Datum, context: any) => {
return context.getCenter().x()
},
y: (datum: Datum, context: any) => {
return context.getCenter().y()
}
}
},
{
name: 'arc_inner',
type: 'symbol',
// dataId: 'id0',
style: {
interactive: false,
size: (datum: Datum, context: any) => {
return context.getLayoutRadius() * 2 * spec.innerRadius - 100
},
fillOpacity: 0,
lineWidth: 1,
strokeOpacity: 0.5,
stroke: {
gradient: 'conical',
startAngle: 0,
endAngle: Math.PI * 2,
stops: [
{
offset: 0,
color: '#FFF',
opacity: 0
},
{
offset: 1,
color: '#FFF',
opacity: 1
}
]
},
visible: true,
x: (datum: Datum, context: any) => {
return context.getCenter().x()
},
y: (datum: Datum, context: any) => {
return context.getCenter().y()
}
}
},
{
name: 'arc_outer',
type: 'symbol',
// dataId: 'id0',
style: {
interactive: false,
size: (datum: Datum, context: any) => {
return context.getLayoutRadius() * 2 * spec.outerRadius + 50
},
fillOpacity: 0,
lineWidth: 1,
strokeOpacity: 0.5,
stroke: {
gradient: 'conical',
startAngle: 0,
endAngle: Math.PI * 2,
stops: [
{
offset: 0,
color: '#FFF',
opacity: 0
},
{
offset: 1,
color: '#FFF',
opacity: 1
}
]
},
visible: true,
x: (datum: Datum, context: any) => {
return context.getCenter().x()
},
y: (datum: Datum, context: any) => {
return context.getCenter().y()
}
}
}
},
{
name: 'arc_inner',
type: 'symbol',
// dataId: 'id0',
style: {
interactive: false,
size: (datum: Datum, context: any) => {
return context.getLayoutRadius() * 2 * spec.innerRadius - 100;
},
fillOpacity: 0,
lineWidth: 1,
strokeOpacity: 0.5,
stroke: {
gradient: 'conical',
startAngle: 0,
endAngle: Math.PI * 2,
stops: [
{
offset: 0,
color: '#FFF',
opacity: 0
},
{
offset: 1,
color: '#FFF',
opacity: 1
}
]
},
visible: true,
x: (datum: Datum, context: any) => {
return context.getCenter().x();
},
y: (datum: Datum, context: any) => {
return context.getCenter().y();
}
}
},
{
name: 'arc_outer',
type: 'symbol',
// dataId: 'id0',
style: {
interactive: false,
size: (datum: Datum, context: any) => {
return context.getLayoutRadius() * 2 * spec.outerRadius + 50;
},
fillOpacity: 0,
lineWidth: 1,
strokeOpacity: 0.5,
stroke: {
gradient: 'conical',
startAngle: 0,
endAngle: Math.PI * 2,
stops: [
{
offset: 0,
color: '#FFF',
opacity: 0
},
{
offset: 1,
color: '#FFF',
opacity: 1
}
]
},
visible: true,
x: (datum: Datum, context: any) => {
return context.getCenter().x();
},
y: (datum: Datum, context: any) => {
return context.getCenter().y();
}
}
}
]
// console.log('spec-pie-transform', spec)
]
}
return spec
}
}

View File

@ -1,5 +1,5 @@
<template>
<collapse-item v-model:name="axis.name">
<collapse-item :name="axis.name">
<template #header>
<n-switch v-model:value="axis.visible" size="small"></n-switch>
</template>

View File

@ -26,14 +26,14 @@
</template>
<script setup lang="ts">
import { PropType, toRefs } from 'vue'
import { PropType } from 'vue'
import { fontStyleConfig } from '@/packages/chartConfiguration/vcharts/index'
import { FontType } from '@/settings/vchartThemes/index'
import { SettingItem } from '@/components/Pages/ChartItemSetting'
defineProps({
style: {
type: Object as PropType<FontType>,
type: Object as PropType<any>,
required: true
}
})

View File

@ -1 +1,2 @@
export * from './legends'
export * from './legends'
export * from './label'

View File

@ -0,0 +1,24 @@
export const labelConfig = {
position: [
{
label: '外部',
value: 'outside'
},
{
label: '内部',
value: 'inside'
},
{
label: '内部-外',
value: 'inside-outer'
},
{
label: '内部-里',
value: 'inside-inner'
},
{
label: '内部-居中',
value: 'inside-center'
}
]
}

View File

@ -66,7 +66,7 @@
:options="labelConfig.fontWeight"
/>
</SettingItem>
<setting-item name="文字边框大小" v-if="optionData.series[0].label.textBorderWidth">
<setting-item name="文字边框大小" v-if="optionData.series[0].label.textBorderWidth > -1">
<n-input-number
v-model:value="optionData.series[0].label.textBorderWidth"
size="small"

View File

@ -5,7 +5,7 @@ export const VChartBarCommonConfig: ConfigType = {
key: 'VChartBarCommon',
chartKey: 'VVChartBarCommon',
conKey: 'VCVChartBarCommon',
title: 'VChart并列柱状图',
title: '并列柱状图-VChart',
category: ChatCategoryEnum.BAR,
categoryName: ChatCategoryEnumName.BAR,
package: PackagesCategoryEnum.VCHART,

View File

@ -5,7 +5,7 @@ export const VChartBarCrossrangeConfig: ConfigType = {
key: 'VChartBarCrossrange',
chartKey: 'VVChartBarCrossrange',
conKey: 'VCVChartBarCrossrange',
title: 'VChart并列柱状图',
title: '并列柱状图-VChart',
category: ChatCategoryEnum.BAR,
categoryName: ChatCategoryEnumName.BAR,
package: PackagesCategoryEnum.VCHART,

View File

@ -5,7 +5,7 @@ export const VChartBarStackConfig: ConfigType = {
key: 'VChartBarStack',
chartKey: 'VVChartBarStack',
conKey: 'VCVChartBarStack',
title: 'VChart堆叠柱状图',
title: '堆叠柱状图-VChart',
category: ChatCategoryEnum.BAR,
categoryName: ChatCategoryEnumName.BAR,
package: PackagesCategoryEnum.VCHART,

View File

@ -5,7 +5,7 @@ export const VChartFunnelConfig: ConfigType = {
key: 'VChartFunnel',
chartKey: 'VVChartFunnel',
conKey: 'VCVChartFunnel',
title: 'VChart漏斗图',
title: '漏斗图-VChart',
category: ChatCategoryEnum.FUNNEL,
categoryName: ChatCategoryEnumName.FUNNEL,
package: PackagesCategoryEnum.VCHART,

View File

@ -5,7 +5,7 @@ export const VChartLineConfig: ConfigType = {
key: 'VChartLine',
chartKey: 'VVChartLine',
conKey: 'VCVChartLine',
title: 'VChart折线图',
title: '折线图-VChart',
category: ChatCategoryEnum.LINE,
categoryName: ChatCategoryEnumName.LINE,
package: PackagesCategoryEnum.VCHART,

View File

@ -4,7 +4,8 @@ import { CreateComponentType } from '@/packages/index.d'
import { vChartOptionPrefixHandle } from '@/packages/public/vChart'
import data from './data.json'
import cloneDeep from 'lodash/cloneDeep'
import { IPieOption } from '../../index.d'
import type { ChatCategoryEnum, IPieOption } from '../../index.d'
import axisThemeJson from '@/settings/vchartThemes/axis.theme.json'
export const includes = ['legends', 'tooltip']
export const option: IPieOption & { dataset?: any } = {
@ -14,8 +15,25 @@ export const option: IPieOption & { dataset?: any } = {
categoryField: 'year',
valueField: 'value',
seriesField: 'year',
// 中心
centerX: '50%',
centerY: '50%',
innerRadius: 0.68,
outerRadius: 0.75,
label: {
visible: true,
position: 'outside',
style: {
fontSize: 12,
fill: '#B9B8CE',
fontFamily: 'SimSun',
fontWeight: 'normal',
angle: 0
}
},
// 业务配置后续会被转换为图表spec)
category: VChartPieConfig.category,
category: VChartPieConfig.category as ChatCategoryEnum.PIE,
extensionMark: []
}
export default class Config extends PublicConfigClass implements CreateComponentType {

View File

@ -1,17 +1,68 @@
<template>
<!-- vCharts 全局设置 -->
<VChartGlobalSetting :optionData="optionData"></VChartGlobalSetting>
<!-- 饼图配制 -->
<collapse-item name="饼图" expanded>
<SettingItemBox name="图形">
<setting-item name="内圈范围">
<n-input-number v-model:value="optionData.innerRadius" :step="0.1" :min="0" size="small"></n-input-number>
</setting-item>
<setting-item name="外圈范围">
<n-input-number v-model:value="optionData.outerRadius" :step="0.1" :min="0" size="small"></n-input-number>
</setting-item>
<setting-item name="中心轴X">
<n-input v-model:value="optionData.centerX" :step="1" :min="0" size="small"></n-input>
</setting-item>
<setting-item name="中心轴Y">
<n-input v-model:value="optionData.centerY" :step="1" :min="0" size="small"></n-input>
</setting-item>
</SettingItemBox>
<SettingItemBox name="标签">
<SettingItem>
<n-space>
<n-switch v-model:value="optionData.label.visible" size="small"></n-switch>
<n-text>展示标签</n-text>
</n-space>
</SettingItem>
<SettingItem name="位置">
<n-select v-model:value="optionData.label.position" :options="labelConfig.position" size="small" />
</SettingItem>
<FontStyle :style="toRefs(optionData.label.style)"></FontStyle>
</SettingItemBox>
<setting-item-box name="内环形">
<setting-item name="可见性">
<n-space>
<n-switch v-model:value="extensionMarkRef" size="small" @update:value="markerHandle"></n-switch>
</n-space>
</setting-item>
</setting-item-box>
</collapse-item>
</template>
<script setup lang="ts">
import { PropType } from 'vue'
import { PropType, ref, toRefs } from 'vue'
import { VChartGlobalSetting } from '@/components/Pages/VChartItemSetting'
import { vChartGlobalThemeJsonType } from '@/settings/vchartThemes/index'
import FontStyle from '@/components/Pages/VChartItemSetting/common/FontStyle.vue'
import type { vChartGlobalThemeJsonType } from '@/settings/vchartThemes/index'
import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import { labelConfig } from '@/packages/chartConfiguration/vcharts/index'
defineProps({
const props = defineProps({
optionData: {
type: Object as PropType<vChartGlobalThemeJsonType>,
required: true
}
})
const a = toRefs(props.optionData.label.style)
const extensionMarkRef = ref(!!props.optionData?.extensionMark)
const markerHandle = (value: boolean) => {
if (value) {
props.optionData.extensionMark = []
} else {
delete props.optionData.extensionMark
}
}
</script>

View File

@ -5,7 +5,7 @@ export const VChartPieConfig: ConfigType = {
key: 'VChartPie',
chartKey: 'VVChartPie',
conKey: 'VCVChartPie',
title: 'VChart饼图',
title: '饼图多欢-VChart',
category: ChatCategoryEnum.PIE,
categoryName: ChatCategoryEnumName.PIE,
package: PackagesCategoryEnum.VCHART,

View File

@ -5,7 +5,7 @@ export const VChartScatterConfig: ConfigType = {
key: 'VChartScatter',
chartKey: 'VVChartScatter',
conKey: 'VCVChartScatter',
title: 'VChart散点图',
title: '散点图-VChart',
category: ChatCategoryEnum.SCATTER,
categoryName: ChatCategoryEnumName.SCATTER,
package: PackagesCategoryEnum.VCHART,

View File

@ -5,7 +5,7 @@ export const VChartWordCloudConfig: ConfigType = {
key: 'VChartWordCloud',
chartKey: 'VVChartWordCloud',
conKey: 'VCVChartWordCloud',
title: 'VChart词云图',
title: '词云图-VChart',
category: ChatCategoryEnum.WORDCLOUD,
categoryName: ChatCategoryEnumName.WORDCLOUD,
package: PackagesCategoryEnum.VCHART,

View File

@ -56,7 +56,7 @@ export interface IAreaOption extends Omit<IAreaChartSpec, 'axes'> {
}
export interface IPieOption extends IPieChartSpec {
category: ChatCategoryEnum.PIE
category?: ChatCategoryEnum.PIE
type: 'pie'
}