feat: 初始化图表整体流程

This commit is contained in:
奔跑的面条 2024-12-15 12:48:36 +08:00
parent 0972ea0e28
commit 6106a8fc5c
21 changed files with 381 additions and 28 deletions

View File

@ -133,13 +133,17 @@ const emit = defineEmits([
const props = defineProps({
option: {
type: Object as PropType<ISpec>,
type: Object as PropType<
ISpec & {
dataset: any
}
>,
required: true
},
initOptions: {
type: Object as PropType<
IInitOption & {
deepWatch?: boolean
deepWatch?: boolean | number
}
>,
required: false,
@ -150,27 +154,53 @@ const props = defineProps({
const vChartRef = ref()
let chart: IVChart
// data
watch(
() => props.option,
(chartProps: ISpec) => {
() => ({
...props.option,
data: undefined
}),
() => {
nextTick(() => {
createOrUpdateChart(props.option)
})
},
{
deep: props.initOptions?.deepWatch || true,
immediate: true
}
)
//
watch(
() => props.option.dataset,
() => {
if (vChartRef.value) {
nextTick(() => {
createOrUpdateChart(chartProps)
createOrUpdateChart(props.option)
})
}
},
{
deep: props.initOptions.deepWatch || false
deep: false,
immediate: false
}
)
//
const createOrUpdateChart = (chartProps: ISpec) => {
const createOrUpdateChart = (
chartProps: ISpec & {
dataset: any
}
) => {
if (vChartRef.value && !chart) {
chart = new VChart(chartProps, {
dom: vChartRef.value,
...props.initOptions
})
chart = new VChart(
{ ...chartProps, data: chartProps.dataset },
{
dom: vChartRef.value,
...props.initOptions
}
)
chart.renderSync()
return true
} else if (chart) {
@ -194,11 +224,6 @@ const eventHandlers = (eventData: MouseEvent, eventName: string) => {
if (event.includes(eventName)) emit(eventName as any, eventData)
}
//
onMounted(() => {
createOrUpdateChart(props.option)
})
//
onBeforeUnmount(() => {
if (chart) {

View File

@ -0,0 +1,45 @@
<template>
<!-- todo 补充常用配置项 -->
<div v-if="optionData.legends">
<div v-for="(legendItem, index) in optionData.legends" :key="index">
<collapse-item name="图例">
<template #header>
<n-switch v-model:value="legendItem.visible" size="small"></n-switch>
</template>
<setting-item-box name="布局">
<setting-item name="位置">
<n-select v-model:value="legendItem.orient" size="small" :options="legendsConfig.orient" />
</setting-item>
<setting-item name="对齐方式">
<n-select v-model:value="legendItem.position" size="small" :options="legendsConfig.position" />
</setting-item>
</setting-item-box>
<setting-item-box name="项配置">
<setting-item name="标题位置">
<n-select v-model:value="legendItem.item.align" size="small" :options="legendsConfig.align" />
</setting-item>
<setting-item name="颜色">
<n-color-picker size="small" v-model:value="legendItem.item.label.style.fill"></n-color-picker>
</setting-item>
<setting-item name="大小">
<n-input-number v-model:value="legendItem.item.label.style.fontSize" :min="1" size="small"></n-input-number>
</setting-item>
</setting-item-box>
</collapse-item>
</div>
</div>
</template>
<script setup lang="ts">
import { PropType } from 'vue'
import { legendsConfig } from '@/packages/chartConfiguration/vcharts/index'
import { vChartGlobalThemeJsonType } from '@/settings/vchartThemes/index'
import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
defineProps({
optionData: {
type: Object as PropType<vChartGlobalThemeJsonType>,
required: true
}
})
</script>

View File

@ -0,0 +1,18 @@
<template>
<!-- 图例 -->
<Legends :optionData="optionData"></Legends>
</template>
<script setup lang="ts">
import { PropType, computed } from 'vue'
import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
import { vChartGlobalThemeJsonType } from '@/settings/vchartThemes/index'
import Legends from './Legends.vue'
const props = defineProps({
optionData: {
type: Object as PropType<vChartGlobalThemeJsonType>,
required: true
}
})
</script>

View File

@ -0,0 +1,3 @@
import VChartGlobalSetting from './VChartGlobalSetting.vue'
export { VChartGlobalSetting }

View File

@ -5,4 +5,5 @@ export * from '@/hooks/useChartDataFetch.hook'
export * from '@/hooks/useChartDataPondFetch.hook'
export * from '@/hooks/useLifeHandler.hook'
export * from '@/hooks/useLang.hook'
export * from '@/hooks/useChartInteract.hook'
export * from '@/hooks/useChartInteract.hook'
export * from '@/hooks/useVCharts.hook'

View File

@ -0,0 +1,82 @@
import { watch } from 'vue'
import vScreenVolcanoBlue from '@visactor/vchart-theme/public/vScreenVolcanoBlue.json'
import { VChart, type ITheme } from '@visactor/vchart'
const themeMap = {
vScreenVolcanoBlue: vScreenVolcanoBlue
}
export const useVCharts = () => {
// 注册主题(支持自定义主题)
const registerTheme = (themeName: keyof typeof themeMap, theme: any) => {
VChart.ThemeManager.registerTheme(themeName, (themeMap[themeName] as any) || theme)
}
// 设置当前主题
const setCurrentTheme = (themeName = 'vScreenVolcanoBlue') => {
VChart.ThemeManager.setCurrentTheme(themeName)
}
// 判断主题是否存在
const themeExist = (name: string): boolean => {
return VChart.ThemeManager.themeExist(name)
}
// 获取主题
const getTheme = (name: string): ITheme => {
return VChart.ThemeManager.getTheme(name)
}
// 获取当前主题
const getCurrentTheme = (): ITheme => {
return VChart.ThemeManager.getCurrentTheme()
}
// 设置主题
const setTheme = (name: keyof typeof themeMap): boolean => {
if (themeExist(name)) {
setCurrentTheme(name)
return true
} else {
// 先注册
const theme = themeMap[name]
if (theme) {
registerTheme(name, theme)
setCurrentTheme(name)
return true
} else {
// 注册默认主题
registerTheme('vScreenVolcanoBlue', vScreenVolcanoBlue)
}
}
return false
}
return {
registerTheme,
setCurrentTheme,
themeExist,
getTheme,
setTheme,
getCurrentTheme
}
}
// 设置全局的 vCharts 主题
export const useInitVChartsTheme = (chartEditStore: any) => {
const vCharts = useVCharts()
const initVChartsThemeIns = watch(
() => chartEditStore.getEditCanvasConfig.vChartThemeName,
(newTheme: string) => {
vCharts.setTheme(newTheme as any)
},
{
immediate: true
}
)
return {
initVChartsThemeIns
}
}

View File

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

View File

@ -0,0 +1,47 @@
export const legendsConfig = {
// 位置
orient: [
{
label: '顶部',
value: 'top'
},
{
label: '底部',
value: 'bottom'
},
{
label: '左侧',
value: 'left'
},
{
label: '右侧',
value: 'right'
}
],
// 对齐方式
position: [
{
label: '起始',
value: 'start'
},
{
label: '居中',
value: 'middle'
},
{
label: '末尾',
value: 'end'
}
],
// 每一项的图例位置
align: [
{
label: '居左',
value: 'left'
},
{
label: '居右',
value: 'right'
}
]
}

View File

@ -28,7 +28,7 @@ export const option = {
type: 'shadow'
}
},
xAxis: {
xAxis: {
show: true,
type: 'category'
},

View File

@ -1,15 +1,24 @@
import { PublicConfigClass } from '@/packages/public'
import { VChartBarCommonConfig } from './index'
import { CreateComponentType } from '@/packages/index.d'
import { vChartOptionPrefixHandle } from '@/packages/public/vChart'
import data from './data.json'
import cloneDeep from 'lodash/cloneDeep'
import { type ISpec } from '@visactor/vchart'
export const option = {
export const includes = ['legends']
export const option: ISpec & { dataset?: any } = {
type: 'bar',
dataset: data,
stack: true,
xField: 'type',
yField: 'value',
seriesField: 'country'
}
export default class Config extends PublicConfigClass implements CreateComponentType {
public key = VChartBarCommonConfig.key
public chartConfig = cloneDeep(VChartBarCommonConfig)
// 图表配置项
public option = cloneDeep(option)
public option = vChartOptionPrefixHandle(option, includes)
}

View File

@ -1,3 +1,17 @@
<template></template>
<template>
<!-- vCharts 全局设置 -->
<VChartGlobalSetting :optionData="optionData"></VChartGlobalSetting>
</template>
<script setup lang="ts"></script>
<script setup lang="ts">
import { PropType, computed } from 'vue'
import { VChartGlobalSetting } from '@/components/Pages/VChartItemSetting'
import { vChartGlobalThemeJsonType } from '@/settings/vchartThemes/index'
defineProps({
optionData: {
type: Object as PropType<vChartGlobalThemeJsonType>,
required: true
}
})
</script>

View File

@ -0,0 +1,22 @@
{
"values": [
{ "type": "Nail polish", "country": "Africa", "value": 4229 },
{ "type": "Nail polish", "country": "EU", "value": 4376 },
{ "type": "Eyebrow pencil", "country": "Africa", "value": 3932 },
{ "type": "Eyebrow pencil", "country": "EU", "value": 3987 },
{ "type": "Rouge", "country": "Africa", "value": 5221 },
{ "type": "Rouge", "country": "EU", "value": 3574 },
{ "type": "Lipstick", "country": "Africa", "value": 9256 },
{ "type": "Lipstick", "country": "EU", "value": 4376 },
{ "type": "Eyeshadows", "country": "Africa", "value": 3308 },
{ "type": "Eyeshadows", "country": "EU", "value": 4572 },
{ "type": "Eyeliner", "country": "Africa", "value": 5432 },
{ "type": "Eyeliner", "country": "EU", "value": 3417 },
{ "type": "Foundation", "country": "Africa", "value": 13701 },
{ "type": "Foundation", "country": "EU", "value": 5231 },
{ "type": "Lip gloss", "country": "Africa", "value": 4008 },
{ "type": "Lip gloss", "country": "EU", "value": 4572 },
{ "type": "Mascara", "country": "Africa", "value": 18712 },
{ "type": "Mascara", "country": "EU", "value": 6134 }
]
}

View File

@ -0,0 +1,22 @@
<template>
<GoVChart ref="vChartRef" :option="chartConfig.option"> </GoVChart>
</template>
<script setup lang="ts">
import { PropType } from 'vue'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { GoVChart } from '@/components/GoVChart'
import { useChartDataFetch } from '@/hooks'
import config from './config'
const props = defineProps({
chartConfig: {
type: Object as PropType<config>,
required: true
}
})
const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore, (newData: any) => {
props.chartConfig.option.dataset = newData
})
</script>

View File

@ -20,7 +20,7 @@ export const mergeTheme = <T, U>(option: T, themeSetting: U, includes: string[])
* @param option
* @return option
*/
export const echartOptionProfixHandle = (option: any, includes: string[]) => {
export const echartOptionProfixHandle = (option: any, includes: string[] = []) => {
option['backgroundColor'] = 'rgba(0,0,0,0)'
return mergeTheme(option, globalThemeJson, includes)
}

View File

@ -0,0 +1,24 @@
import merge from 'lodash/merge'
import pick from 'lodash/pick'
import { vChartGlobalThemeJson } from '@/settings/vchartThemes/index'
/**
* * color
* @param option
* @param themeSetting
* @param excludes
* @returns object
*/
export const mergeTheme = <T, U>(option: T, themeSetting: U, includes: string[]) => {
return (option = merge({}, pick(themeSetting, includes), option))
}
/**
* * vCharts option
* @param option
* @return option
*/
export const vChartOptionPrefixHandle = (option: any, includes: string[] = []) => {
option['background'] = 'rgba(0,0,0,0)'
return mergeTheme(option, vChartGlobalThemeJson, includes)
}

View File

@ -0,0 +1,19 @@
{
"legends": [
{
"visible": true,
"position": "middle",
"orient": "bottom",
"item": {
"visible": true,
"align": "left",
"label": {
"style": {
"fontSize": 16,
"fill": "#B9B8CE"
}
}
}
}
]
}

View File

@ -0,0 +1,9 @@
import themeJson from './global.theme.json'
type ThemeJsonType = typeof themeJson
export interface vChartGlobalThemeJsonType extends Partial<ThemeJsonType> {
dataset?: any
[T: string]: any
}
export const vChartGlobalThemeJson = { ...themeJson, dataset: null, renderer: 'svg' as const }

View File

@ -57,6 +57,7 @@ export enum EditCanvasConfigEnum {
CHART_THEME_COLOR = 'chartThemeColor',
CHART_CUSTOM_THEME_COLOR_INFO = 'chartCustomThemeColorInfo',
CHART_THEME_SETTING = 'chartThemeSetting',
VCHART_THEME_NAME = 'vChartThemeName',
BACKGROUND = 'background',
BACKGROUND_IMAGE = 'backgroundImage',
SELECT_COLOR = 'selectColor',
@ -100,7 +101,9 @@ export interface EditCanvasConfigType {
// 图表全局配置
[EditCanvasConfigEnum.CHART_THEME_SETTING]: GlobalThemeJsonType
// 图表主题颜色
[EditCanvasConfigEnum.SELECT_COLOR]: boolean
[EditCanvasConfigEnum.SELECT_COLOR]: boolean,
// vChart 主题
[EditCanvasConfigEnum.VCHART_THEME_NAME]: string
// 预览展示方式
[EditCanvasConfigEnum.PREVIEW_SCALE_TYPE]: PreviewScaleEnum
}

View File

@ -114,6 +114,8 @@ export const useChartEditStore = defineStore({
chartCustomThemeColorInfo: undefined,
// 全局配置
chartThemeSetting: globalThemeJson,
// vChart 主题
vChartThemeName: 'vScreenVolcanoBlue',
// 适配方式
previewScaleType: previewScaleType
},

View File

@ -83,7 +83,7 @@
</template>
<script lang="ts" setup>
import { onMounted, computed, provide } from 'vue'
import { onMounted, computed, provide, watch } from 'vue'
import { chartColors } from '@/settings/chartThemes/index'
import { MenuEnum } from '@/enums/editPageEnum'
import { CreateComponentType, CreateComponentGroupType } from '@/packages/index.d'
@ -96,6 +96,7 @@ import { useLayout } from './hooks/useLayout.hook'
import { useAddKeyboard } from '../hooks/useKeyboard.hook'
import { dragHandle, dragoverHandle, mousedownHandleUnStop, useMouseHandle } from './hooks/useDrag.hook'
import { useComponentStyle, useSizeStyle } from './hooks/useStyle.hook'
import { useInitVChartsTheme } from '@/hooks'
import { ContentBox } from '../ContentBox/index'
import { EditGroup } from './components/EditGroup'
@ -149,7 +150,7 @@ const themeSetting = computed(() => {
//
const themeColor = computed(() => {
const colorCustomMergeData = colorCustomMerge(chartEditStore.getEditCanvasConfig.chartCustomThemeColorInfo)
const colorCustomMergeData: any = colorCustomMerge(chartEditStore.getEditCanvasConfig.chartCustomThemeColorInfo)
return colorCustomMergeData[chartEditStore.getEditCanvasConfig.chartThemeColor]
})
@ -170,7 +171,6 @@ const rangeStyle = computed(() => {
? { background: backgroundColor }
: { background: `url(${backgroundImage}) no-repeat center center / cover !important` }
// @ts-ignore
return {
...computedBackground,
width: 'inherit',
@ -178,6 +178,9 @@ const rangeStyle = computed(() => {
}
})
// vChart
useInitVChartsTheme(chartEditStore)
//
onMounted(() => {
useAddKeyboard()

View File

@ -37,6 +37,7 @@ import { useStore } from './hooks/useStore.hook'
import { PreviewScaleEnum } from '@/enums/styleEnum'
import type { ChartEditStorageType } from './index.d'
import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
import { useInitVChartsTheme } from '@/hooks'
// const localStorageInfo: ChartEditStorageType = getSessionStorageInfo() as ChartEditStorageType
@ -64,6 +65,9 @@ const { show } = useComInstall(chartEditStore)
//
keyRecordHandle()
// vChart
useInitVChartsTheme(chartEditStore)
</script>
<style lang="scss" scoped>