feat: 新增饼图轮播功能

This commit is contained in:
奔跑的面条 2023-05-16 19:48:06 +08:00
parent 6bbe489162
commit c18bc019d3
3 changed files with 252 additions and 152 deletions

View File

@ -18,7 +18,14 @@ export const PieTypeObject = {
[PieTypeEnum.ROSE]: 'rose' [PieTypeEnum.ROSE]: 'rose'
} }
// 其它配置
const otherConfig = {
// 轮播动画
isCarousel: false,
}
const option = { const option = {
...otherConfig,
type: 'ring', type: 'ring',
tooltip: { tooltip: {
show: true, show: true,

View File

@ -1,88 +1,99 @@
<template> <template>
<!-- Echarts 全局设置 --> <!-- Echarts 全局设置 -->
<global-setting :optionData="optionData"></global-setting> <global-setting :optionData="optionData"></global-setting>
<CollapseItem name="饼图配置" :expanded="true"> <CollapseItem name="饼图配置" :expanded="true">
<SettingItemBox name="类型"> <SettingItemBox name="类型">
<SettingItem> <SettingItem>
<n-select v-model:value="optionData.type" size="small" :options="fontWeightOptions" /> <n-select v-model:value="optionData.type" size="small" :options="fontWeightOptions" />
</SettingItem> </SettingItem>
</SettingItemBox> </SettingItemBox>
<SettingItemBox name="标签"> <SettingItemBox name="动画" :alone="true">
<SettingItem> <SettingItem>
<n-space> <n-space>
<n-switch v-model:value="optionData.series[0].label.show" size="small"></n-switch> <n-switch v-model:value="optionData.isCarousel" size="small"></n-switch>
<n-text>展示标签</n-text> <n-text>开启<n-text :depth="3">将自动隐藏图例</n-text></n-text>
</n-space> </n-space>
</SettingItem> </SettingItem>
<setting-item> <SettingItem>
<n-space> <n-text :depth="3">无鼠标点击图例场景时可强行打开图例</n-text>
<n-switch v-model:value="optionData.series[0].labelLine.show" size="small"></n-switch> </SettingItem>
<n-text>引导线</n-text> </SettingItemBox>
</n-space> <SettingItemBox name="标签">
</setting-item> <SettingItem>
<SettingItem name="位置"> <n-space>
<n-select v-model:value="optionData.series[0].label.position" size="small" :options="labelConfig.position" /> <n-switch v-model:value="optionData.series[0].label.show" size="small"></n-switch>
</SettingItem> <n-text>展示标签</n-text>
<setting-item name="展示类型"> </n-space>
<n-select v-model:value="optionData.series[0].label.formatter" size="small" :options="labelFormatterOptions" /> </SettingItem>
</setting-item> <setting-item>
</SettingItemBox> <n-space>
<setting-item-box name="圆角"> <n-switch v-model:value="optionData.series[0].labelLine.show" size="small"></n-switch>
<setting-item> <n-text>引导线</n-text>
<n-space> </n-space>
<n-input-number </setting-item>
v-model:value="optionData.series[0].itemStyle.borderRadius" <SettingItem name="位置">
size="small" <n-select v-model:value="optionData.series[0].label.position" size="small" :options="labelConfig.position" />
:min="0" </SettingItem>
></n-input-number> <setting-item name="展示类型">
<n-text>圆角大小</n-text> <n-select v-model:value="optionData.series[0].label.formatter" size="small" :options="labelFormatterOptions" />
</n-space> </setting-item>
</setting-item> </SettingItemBox>
<setting-item> <setting-item-box name="圆角">
<n-space> <setting-item>
<n-input-number <n-space>
v-model:value="optionData.series[0].itemStyle.borderWidth" <n-input-number
size="small" v-model:value="optionData.series[0].itemStyle.borderRadius"
:min="0" size="small"
></n-input-number> :min="0"
<n-text>线条宽度</n-text> ></n-input-number>
</n-space> <n-text>圆角大小</n-text>
</setting-item> </n-space>
</setting-item-box> </setting-item>
</CollapseItem> <setting-item>
</template> <n-space>
<n-input-number
<script setup lang="ts"> v-model:value="optionData.series[0].itemStyle.borderWidth"
import { PropType, watch } from 'vue' size="small"
import { GlobalThemeJsonType } from '@/settings/chartThemes/index' :min="0"
import { GlobalSetting, CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting' ></n-input-number>
import { PieTypeObject, PieTypeEnum } from './config' <n-text>线条宽度</n-text>
import { labelConfig } from '@/packages/chartConfiguration/echarts' </n-space>
</setting-item>
const props = defineProps({ </setting-item-box>
optionData: { </CollapseItem>
type: Object as PropType<GlobalThemeJsonType>, </template>
required: true
} <script setup lang="ts">
}) import { PropType, watch } from 'vue'
const fontWeightOptions = [ import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
{ import { GlobalSetting, CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
label: PieTypeEnum.NORMAL, import { PieTypeObject, PieTypeEnum } from './config'
value: PieTypeObject[PieTypeEnum.NORMAL] import { labelConfig } from '@/packages/chartConfiguration/echarts'
},
{ const props = defineProps({
label: PieTypeEnum.RING, optionData: {
value: PieTypeObject[PieTypeEnum.RING] type: Object as PropType<GlobalThemeJsonType>,
}, required: true
{ }
label: PieTypeEnum.ROSE, })
value: PieTypeObject[PieTypeEnum.ROSE] const fontWeightOptions = [
} {
] label: PieTypeEnum.NORMAL,
value: PieTypeObject[PieTypeEnum.NORMAL]
const labelFormatterOptions = [ },
{ label: '数据名', value: '{b}' }, {
{ label: '百分比', value: '{d}' }, label: PieTypeEnum.RING,
{ label: '列名:百分比', value: '{b}:{d}%' } value: PieTypeObject[PieTypeEnum.RING]
] },
</script> {
label: PieTypeEnum.ROSE,
value: PieTypeObject[PieTypeEnum.ROSE]
}
]
const labelFormatterOptions = [
{ label: '数据名', value: '{b}' },
{ label: '百分比', value: '{d}' },
{ label: '列名:百分比', value: '{b}:{d}%' }
]
</script>

View File

@ -1,64 +1,146 @@
<template> <template>
<v-chart ref="vChartRef" :init-options="initOptions" :theme="themeColor" :option="option" :manual-update="isPreview()" autoresize></v-chart> <v-chart
</template> ref="vChartRef"
autoresize
<script setup lang="ts"> :init-options="initOptions"
import { computed, PropType, reactive, watch } from 'vue' :theme="themeColor"
import VChart from 'vue-echarts' :option="option"
import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook' :manual-update="isPreview()"
import { use } from 'echarts/core' @mouseover="handleHighlight"
import { CanvasRenderer } from 'echarts/renderers' @mouseout="handleDownplay"
import { PieChart } from 'echarts/charts' ></v-chart>
import { mergeTheme } from '@/packages/public/chart' </template>
import config, { includes } from './config'
import { useChartDataFetch } from '@/hooks' <script setup lang="ts">
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore' import { computed, PropType, onMounted, watch } from 'vue'
import { isPreview } from '@/utils' import VChart from 'vue-echarts'
import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components' import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
import { use } from 'echarts/core'
const props = defineProps({ import { CanvasRenderer } from 'echarts/renderers'
themeSetting: { import { PieChart } from 'echarts/charts'
type: Object, import { mergeTheme } from '@/packages/public/chart'
required: true import config, { includes } from './config'
}, import { useChartDataFetch } from '@/hooks'
themeColor: { import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
type: Object, import { isPreview } from '@/utils'
required: true import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
}, import dataJson from './data.json'
chartConfig: {
type: Object as PropType<config>, const props = defineProps({
required: true themeSetting: {
} type: Object,
}) required: true
},
const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting) themeColor: {
type: Object,
use([DatasetComponent, CanvasRenderer, PieChart, GridComponent, TooltipComponent, LegendComponent]) required: true
},
const option = computed(() => { chartConfig: {
return mergeTheme(props.chartConfig.option, props.themeSetting, includes) type: Object as PropType<config>,
}) required: true
}
watch( })
() => props.chartConfig.option.type, const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
newData => { let seriesDataNum = -1
try { let seriesDataMaxLength = 0
if (newData === 'nomal') { let intervalInstance: any = null
props.chartConfig.option.series[0].radius = '70%'
props.chartConfig.option.series[0].roseType = false use([DatasetComponent, CanvasRenderer, PieChart, GridComponent, TooltipComponent, LegendComponent])
} else if (newData === 'ring') {
props.chartConfig.option.series[0].radius = ['40%', '65%'] const option = computed(() => {
props.chartConfig.option.series[0].roseType = false return mergeTheme(props.chartConfig.option, props.themeSetting, includes)
} else { })
props.chartConfig.option.series[0].radius = '70%'
props.chartConfig.option.series[0].roseType = true //
} const handleSeriesData = () => {
} catch (error) { if (seriesDataNum > -1) {
console.log(error) vChartRef.value?.dispatchAction({
} type: 'downplay',
}, dataIndex: seriesDataNum
{ deep: false, immediate: true } })
) }
seriesDataNum = seriesDataNum >= seriesDataMaxLength - 1 ? 0 : seriesDataNum + 1
const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore) vChartRef.value?.dispatchAction({
</script> type: 'highlight',
dataIndex: seriesDataNum
})
}
//
const addPieInterval = (newData?: typeof dataJson, skipPre = false) => {
if (!skipPre && !Array.isArray(newData?.source)) return
if (!skipPre) seriesDataMaxLength = newData?.source.length || 0
clearInterval(intervalInstance)
intervalInstance = setInterval(() => {
handleSeriesData()
}, 1000)
}
//
const clearPieInterval = () => {
vChartRef.value?.dispatchAction({
type: 'downplay',
dataIndex: seriesDataNum
})
clearInterval(intervalInstance)
intervalInstance = null
}
//
const handleHighlight = () => {
clearPieInterval()
}
//
const handleDownplay = () => {
if (props.chartConfig.option.isCarousel && !intervalInstance) {
//
addPieInterval(undefined, true)
}
}
watch(
() => props.chartConfig.option.type,
newData => {
try {
if (newData === 'nomal') {
props.chartConfig.option.series[0].radius = '70%'
props.chartConfig.option.series[0].roseType = false
} else if (newData === 'ring') {
props.chartConfig.option.series[0].radius = ['40%', '65%']
props.chartConfig.option.series[0].roseType = false
} else {
props.chartConfig.option.series[0].radius = '70%'
props.chartConfig.option.series[0].roseType = true
}
} catch (error) {
console.log(error)
}
},
{ deep: false, immediate: true }
)
watch(
() => props.chartConfig.option.isCarousel,
newData => {
if (newData) {
addPieInterval(undefined, true)
props.chartConfig.option.legend.show = false
} else {
props.chartConfig.option.legend.show = true
clearPieInterval()
}
}
)
const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore, (newData: typeof dataJson) => {
addPieInterval(newData)
})
onMounted(() => {
seriesDataMaxLength = dataJson.source.length
if (props.chartConfig.option.isCarousel) {
addPieInterval(undefined, true)
}
})
</script>