Commit 06d82be089d77fd10e4d31a9eb5dc55d1d9b7a2e

Authored by fengwotao
1 parent 85d6cbf4

feat(packages/external): 重写部分柱状图和部分折线图,新增开启关闭动画效果

  1 +import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public'
  2 +import { OverrideBarCommonConfig } from './index'
  3 +import { CreateComponentType } from '@/packages/index.d'
  4 +import cloneDeep from 'lodash/cloneDeep'
  5 +import dataJson from './data.json'
  6 +
  7 +export const includes = ['legend', 'xAxis', 'yAxis', 'grid']
  8 +
  9 +// 其它配置项比如新增(动画)
  10 +const otherConfig = {
  11 + // 轮播动画
  12 + isCarousel: false,
  13 +}
  14 +export const seriesItem = {
  15 + type: 'bar',
  16 + barWidth: 15,
  17 + label: {
  18 + show: true,
  19 + position: 'top',
  20 + color: '#fff',
  21 + fontSize: 12
  22 + },
  23 + itemStyle: {
  24 + color: null,
  25 + borderRadius: 2
  26 + }
  27 +}
  28 +export const option = {
  29 + ...otherConfig,
  30 + tooltip: {
  31 + show: true,
  32 + trigger: 'axis',
  33 + axisPointer: {
  34 + show: true,
  35 + type: 'shadow'
  36 + }
  37 + },
  38 +xAxis: {
  39 + show: true,
  40 + type: 'category'
  41 + },
  42 + yAxis: {
  43 + show: true,
  44 + type: 'value'
  45 + },
  46 + dataset: { ...dataJson },
  47 + series: [seriesItem, seriesItem]
  48 +}
  49 +
  50 +export default class Config extends PublicConfigClass implements CreateComponentType {
  51 + public key = OverrideBarCommonConfig.key
  52 + public chartConfig = cloneDeep(OverrideBarCommonConfig)
  53 + // 图表配置项
  54 + public option = echartOptionProfixHandle(option, includes)
  55 +}
... ...
  1 +<template>
  2 + <!-- Echarts 全局设置 -->
  3 + <global-setting :optionData="optionData"></global-setting>
  4 + <CollapseItem v-for="(item, index) in seriesList" :key="index" :name="`柱状图-${index + 1}`" :expanded="true">
  5 + <SettingItemBox name="图形">
  6 + <SettingItem name="宽度">
  7 + <n-input-number
  8 + v-model:value="item.barWidth"
  9 + :min="1"
  10 + :max="100"
  11 + size="small"
  12 + placeholder="自动计算"
  13 + ></n-input-number>
  14 + </SettingItem>
  15 + <SettingItem name="圆角">
  16 + <n-input-number v-model:value="item.itemStyle.borderRadius" :min="0" size="small"></n-input-number>
  17 + </SettingItem>
  18 + </SettingItemBox>
  19 + <SettingItemBox name="动画" :alone="true">
  20 + <SettingItem>
  21 + <n-space>
  22 + <n-switch v-model:value="optionData.isCarousel" size="small"></n-switch>
  23 + <n-text>开启<n-text :depth="3">(将自动隐藏图例)</n-text></n-text>
  24 + </n-space>
  25 + </SettingItem>
  26 + <SettingItem>
  27 + <n-text :depth="3">无鼠标点击图例场景时,可强行打开图例</n-text>
  28 + </SettingItem>
  29 + </SettingItemBox>
  30 + <setting-item-box name="标签">
  31 + <setting-item>
  32 + <n-space>
  33 + <n-switch v-model:value="item.label.show" size="small" />
  34 + <n-text>展示标签</n-text>
  35 + </n-space>
  36 + </setting-item>
  37 + <setting-item name="大小">
  38 + <n-input-number v-model:value="item.label.fontSize" size="small" :min="1"></n-input-number>
  39 + </setting-item>
  40 + <setting-item name="颜色">
  41 + <n-color-picker size="small" :modes="['hex']" v-model:value="item.label.color"></n-color-picker>
  42 + </setting-item>
  43 + <setting-item name="位置">
  44 + <n-select
  45 + v-model:value="item.label.position"
  46 + :options="[
  47 + { label: 'top', value: 'top' },
  48 + { label: 'left', value: 'left' },
  49 + { label: 'right', value: 'right' },
  50 + { label: 'bottom', value: 'bottom' }
  51 + ]"
  52 + />
  53 + </setting-item>
  54 + </setting-item-box>
  55 + </CollapseItem>
  56 +</template>
  57 +
  58 +<script setup lang="ts">
  59 +import { PropType, computed } from 'vue'
  60 +import { GlobalSetting, CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
  61 +import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
  62 +
  63 +const props = defineProps({
  64 + optionData: {
  65 + type: Object as PropType<GlobalThemeJsonType>,
  66 + required: true
  67 + }
  68 +})
  69 +
  70 +const seriesList = computed(() => {
  71 + return props.optionData.series
  72 +})
  73 +</script>
... ...
  1 +{
  2 + "dimensions": ["product", "data1", "data2"],
  3 + "source": [
  4 + {
  5 + "product": "Mon",
  6 + "data1": 120,
  7 + "data2": 130
  8 + },
  9 + {
  10 + "product": "Tue",
  11 + "data1": 200,
  12 + "data2": 130
  13 + },
  14 + {
  15 + "product": "Wed",
  16 + "data1": 150,
  17 + "data2": 312
  18 + },
  19 + {
  20 + "product": "Thu",
  21 + "data1": 80,
  22 + "data2": 268
  23 + },
  24 + {
  25 + "product": "Fri",
  26 + "data1": 70,
  27 + "data2": 155
  28 + },
  29 + {
  30 + "product": "Sat",
  31 + "data1": 110,
  32 + "data2": 117
  33 + },
  34 + {
  35 + "product": "Sun",
  36 + "data1": 130,
  37 + "data2": 160
  38 + }
  39 + ]
  40 +}
... ...
  1 +import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
  2 +import { ChatCategoryEnum, ChatCategoryEnumName } from '@/packages/components/Charts/index.d'
  3 +import { useWidgetKey } from '@/packages/external/useWidgetKey'
  4 +
  5 +const { key, conKey, chartKey } = useWidgetKey('OverrideBarCommon', true)
  6 +
  7 +export const OverrideBarCommonConfig: ConfigType = {
  8 + key,
  9 + chartKey,
  10 + conKey,
  11 + title: '柱状图动画',
  12 + category: ChatCategoryEnum.BAR,
  13 + categoryName: ChatCategoryEnumName.BAR,
  14 + package: PackagesCategoryEnum.CHARTS,
  15 + chartFrame: ChartFrameEnum.ECHARTS,
  16 + image: 'bar_x.png'
  17 +}
... ...
  1 +<template>
  2 + <v-chart
  3 + ref="vChartRef"
  4 + :init-options="initOptions"
  5 + :theme="themeColor"
  6 + :option="option"
  7 + :manual-update="isPreview()"
  8 + :update-options="{
  9 + replaceMerge: replaceMergeArr
  10 + }"
  11 + autoresize
  12 + @mouseover="handleHighlight"
  13 + @mouseout="handleDownplay"
  14 + ></v-chart>
  15 +</template>
  16 +
  17 +<script setup lang="ts">
  18 +import { ref, nextTick, computed, watch, PropType, onMounted } from 'vue'
  19 +import VChart from 'vue-echarts'
  20 +import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
  21 +import { use } from 'echarts/core'
  22 +import { CanvasRenderer } from 'echarts/renderers'
  23 +import { BarChart } from 'echarts/charts'
  24 +import config, { includes, seriesItem } from './config'
  25 +import { mergeTheme } from '@/packages/public/chart'
  26 +import { useChartDataFetch } from '@/hooks'
  27 +import { CreateComponentType } from '@/packages/index.d'
  28 +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
  29 +import { isPreview } from '@/utils'
  30 +import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
  31 +import isObject from 'lodash/isObject'
  32 +import dataJson from './data.json'
  33 +
  34 +const props = defineProps({
  35 + themeSetting: {
  36 + type: Object,
  37 + required: true
  38 + },
  39 + themeColor: {
  40 + type: Object,
  41 + required: true
  42 + },
  43 + chartConfig: {
  44 + type: Object as PropType<config>,
  45 + required: true
  46 + }
  47 +})
  48 +
  49 +const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
  50 +
  51 +use([DatasetComponent, CanvasRenderer, BarChart, GridComponent, TooltipComponent, LegendComponent])
  52 +
  53 +const replaceMergeArr = ref<string[]>()
  54 +
  55 +const option = computed(() => {
  56 + return mergeTheme(props.chartConfig.option, props.themeSetting, includes)
  57 +})
  58 +
  59 +// dataset 无法变更条数的补丁
  60 +watch(
  61 + () => props.chartConfig.option.dataset,
  62 + (newData: { dimensions: any }, oldData) => {
  63 + try {
  64 + if (!isObject(newData) || !('dimensions' in newData)) return
  65 + if (Array.isArray(newData?.dimensions)) {
  66 + const seriesArr = []
  67 + for (let i = 0; i < newData.dimensions.length - 1; i++) {
  68 + seriesArr.push(seriesItem)
  69 + }
  70 + replaceMergeArr.value = ['series']
  71 + props.chartConfig.option.series = seriesArr
  72 + nextTick(() => {
  73 + replaceMergeArr.value = []
  74 + })
  75 + }
  76 + } catch (error) {
  77 + console.log(error)
  78 + }
  79 + },
  80 + {
  81 + deep: false
  82 + }
  83 +)
  84 +
  85 +let seriesDataNum = -1
  86 +let seriesDataMaxLength = 0
  87 +let intervalInstance: any = null
  88 +//轮播时长
  89 +const duration = 1500
  90 +
  91 +// 会重新选择需要选中和展示的数据
  92 +const handleSeriesData = () => {
  93 + if (seriesDataNum > -1) {
  94 + vChartRef.value?.dispatchAction({
  95 + type: 'downplay',
  96 + dataIndex: seriesDataNum
  97 + })
  98 + }
  99 + seriesDataNum = seriesDataNum >= seriesDataMaxLength - 1 ? 0 : seriesDataNum + 1
  100 + vChartRef.value?.dispatchAction({
  101 + type: 'showTip',
  102 + seriesIndex: 0,
  103 + dataIndex: seriesDataNum
  104 + })
  105 +}
  106 +
  107 +// 新增轮播
  108 +const addPieInterval = (newData?: typeof dataJson, skipPre = false) => {
  109 + if (!skipPre && !Array.isArray(newData?.source)) return
  110 + if (!skipPre) seriesDataMaxLength = newData?.source.length || 0
  111 + clearInterval(intervalInstance)
  112 + intervalInstance = setInterval(() => {
  113 + handleSeriesData()
  114 + }, duration)
  115 +}
  116 +
  117 +// 取消轮播
  118 +const clearPieInterval = () => {
  119 + vChartRef.value?.dispatchAction({
  120 + type: 'hideTip',
  121 + seriesIndex: 0,
  122 + dataIndex: seriesDataNum
  123 + })
  124 + vChartRef.value?.dispatchAction({
  125 + type: 'downplay',
  126 + dataIndex: seriesDataNum
  127 + })
  128 + clearInterval(intervalInstance)
  129 + intervalInstance = null
  130 +}
  131 +
  132 +// 处理鼠标聚焦高亮内容
  133 +const handleHighlight = () => {
  134 + clearPieInterval()
  135 +}
  136 +
  137 +// 处理鼠标取消悬浮
  138 +const handleDownplay = () => {
  139 + if (props.chartConfig.option.isCarousel && !intervalInstance) {
  140 + // 恢复轮播
  141 + addPieInterval(undefined, true)
  142 + }
  143 +}
  144 +
  145 +watch(
  146 + () => props.chartConfig.option.isCarousel,
  147 + newData => {
  148 + if (newData) {
  149 + addPieInterval(undefined, true)
  150 + props.chartConfig.option.legend.show = false
  151 + } else {
  152 + props.chartConfig.option.legend.show = true
  153 + clearPieInterval()
  154 + }
  155 + }
  156 +)
  157 +
  158 +const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore, (newData: typeof dataJson) => {
  159 + addPieInterval(newData)
  160 +})
  161 +
  162 +onMounted(() => {
  163 + seriesDataMaxLength = dataJson.source.length
  164 + if (props.chartConfig.option.isCarousel) {
  165 + addPieInterval(undefined, true)
  166 + }
  167 +})
  168 +</script>
... ...
  1 +import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public'
  2 +import { OverrideLineCommonConfig } from './index'
  3 +import { CreateComponentType } from '@/packages/index.d'
  4 +import cloneDeep from 'lodash/cloneDeep'
  5 +import dataJson from './data.json'
  6 +
  7 +export const includes = ['legend', 'xAxis', 'yAxis', 'grid']
  8 +export const seriesItem = {
  9 + type: 'line',
  10 + label: {
  11 + show: true,
  12 + position: 'top',
  13 + color: '#fff',
  14 + fontSize: 12
  15 + },
  16 + symbolSize: 5, //设定实心点的大小
  17 + itemStyle: {
  18 + color: null,
  19 + borderRadius: 0
  20 + },
  21 + lineStyle: {
  22 + type: 'solid',
  23 + width: 3,
  24 + color: null
  25 + }
  26 +}
  27 +// 其它配置项比如新增(动画)
  28 +const otherConfig = {
  29 + // 轮播动画
  30 + isCarousel: false,
  31 +}
  32 +export const option = {
  33 + ...otherConfig,
  34 + tooltip: {
  35 + show: true,
  36 + trigger: 'axis',
  37 + axisPointer: {
  38 + type: 'line'
  39 + }
  40 + },
  41 + xAxis: {
  42 + show: true,
  43 + type: 'category'
  44 + },
  45 + yAxis: {
  46 + show: true,
  47 + type: 'value'
  48 + },
  49 + dataset: { ...dataJson },
  50 + series: [seriesItem, seriesItem]
  51 +}
  52 +
  53 +export default class Config extends PublicConfigClass implements CreateComponentType {
  54 + public key: string = OverrideLineCommonConfig.key
  55 + public chartConfig = cloneDeep(OverrideLineCommonConfig)
  56 + // 图表配置项
  57 + public option = echartOptionProfixHandle(option, includes)
  58 +}
... ...
  1 +<template>
  2 + <!-- Echarts 全局设置 -->
  3 + <global-setting :optionData="optionData"></global-setting>
  4 + <CollapseItem v-for="(item, index) in seriesList" :key="index" :name="`折线图-${index + 1}`" :expanded="true">
  5 + <SettingItemBox name="线条">
  6 + <SettingItem name="宽度">
  7 + <n-input-number
  8 + v-model:value="item.lineStyle.width"
  9 + :min="1"
  10 + :max="100"
  11 + size="small"
  12 + placeholder="自动计算"
  13 + ></n-input-number>
  14 + </SettingItem>
  15 + <SettingItem name="类型">
  16 + <n-select v-model:value="item.lineStyle.type" size="small" :options="lineConf.lineStyle.type"></n-select>
  17 + </SettingItem>
  18 + </SettingItemBox>
  19 + <SettingItemBox name="动画" :alone="true">
  20 + <SettingItem>
  21 + <n-space>
  22 + <n-switch v-model:value="optionData.isCarousel" size="small"></n-switch>
  23 + <n-text>开启<n-text :depth="3">(将自动隐藏图例)</n-text></n-text>
  24 + </n-space>
  25 + </SettingItem>
  26 + <SettingItem>
  27 + <n-text :depth="3">无鼠标点击图例场景时,可强行打开图例</n-text>
  28 + </SettingItem>
  29 + </SettingItemBox>
  30 + <SettingItemBox name="实心点">
  31 + <SettingItem name="大小">
  32 + <n-input-number
  33 + v-model:value="item.symbolSize"
  34 + :min="1"
  35 + :max="100"
  36 + size="small"
  37 + placeholder="自动计算"
  38 + ></n-input-number>
  39 + </SettingItem>
  40 + </SettingItemBox>
  41 + <setting-item-box name="标签">
  42 + <setting-item>
  43 + <n-space>
  44 + <n-switch v-model:value="item.label.show" size="small" />
  45 + <n-text>展示标签</n-text>
  46 + </n-space>
  47 + </setting-item>
  48 + <setting-item name="大小">
  49 + <n-input-number v-model:value="item.label.fontSize" size="small" :min="1"></n-input-number>
  50 + </setting-item>
  51 + <setting-item name="颜色">
  52 + <n-color-picker size="small" :modes="['hex']" v-model:value="item.label.color"></n-color-picker>
  53 + </setting-item>
  54 + <setting-item name="位置">
  55 + <n-select
  56 + v-model:value="item.label.position"
  57 + :options="[
  58 + { label: 'top', value: 'top' },
  59 + { label: 'left', value: 'left' },
  60 + { label: 'right', value: 'right' },
  61 + { label: 'bottom', value: 'bottom' }
  62 + ]"
  63 + />
  64 + </setting-item>
  65 + </setting-item-box>
  66 + </CollapseItem>
  67 +</template>
  68 +
  69 +<script setup lang="ts">
  70 +import { PropType, computed } from 'vue'
  71 +import { lineConf } from '@/packages/chartConfiguration/echarts/index'
  72 +import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
  73 +import { GlobalSetting, CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
  74 +
  75 +const props = defineProps({
  76 + optionData: {
  77 + type: Object as PropType<GlobalThemeJsonType>,
  78 + required: true
  79 + }
  80 +})
  81 +
  82 +const seriesList = computed(() => {
  83 + return props.optionData.series
  84 +})
  85 +</script>
... ...
  1 +{
  2 + "dimensions": ["product", "data1", "data2"],
  3 + "source": [
  4 + {
  5 + "product": "Mon",
  6 + "data1": 120,
  7 + "data2": 130
  8 + },
  9 + {
  10 + "product": "Tue",
  11 + "data1": 200,
  12 + "data2": 130
  13 + },
  14 + {
  15 + "product": "Wed",
  16 + "data1": 150,
  17 + "data2": 312
  18 + },
  19 + {
  20 + "product": "Thu",
  21 + "data1": 80,
  22 + "data2": 268
  23 + },
  24 + {
  25 + "product": "Fri",
  26 + "data1": 70,
  27 + "data2": 155
  28 + },
  29 + {
  30 + "product": "Sat",
  31 + "data1": 110,
  32 + "data2": 117
  33 + },
  34 + {
  35 + "product": "Sun",
  36 + "data1": 130,
  37 + "data2": 160
  38 + }
  39 + ]
  40 +}
... ...
  1 +import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
  2 +import { ChatCategoryEnum, ChatCategoryEnumName } from '@/packages/components/Charts/index.d'
  3 +import { useWidgetKey } from '@/packages/external/useWidgetKey'
  4 +
  5 +const { key, conKey, chartKey } = useWidgetKey('OverrideLineCommon', true)
  6 +
  7 +export const OverrideLineCommonConfig: ConfigType = {
  8 + key,
  9 + chartKey,
  10 + conKey,
  11 + title: '折线图动画',
  12 + category: ChatCategoryEnum.LINE,
  13 + categoryName: ChatCategoryEnumName.LINE,
  14 + package: PackagesCategoryEnum.CHARTS,
  15 + chartFrame: ChartFrameEnum.ECHARTS,
  16 + image: 'line.png'
  17 +}
... ...
  1 +<template>
  2 + <v-chart
  3 + ref="vChartRef"
  4 + :init-options="initOptions"
  5 + :theme="themeColor"
  6 + :option="option"
  7 + :manual-update="isPreview()"
  8 + :update-options="{
  9 + replaceMerge: replaceMergeArr
  10 + }"
  11 + autoresize
  12 + @mouseover="handleHighlight"
  13 + @mouseout="handleDownplay"
  14 + >
  15 + </v-chart>
  16 +</template>
  17 +
  18 +<script setup lang="ts">
  19 +import { PropType, computed, watch, ref, nextTick, onMounted } from 'vue'
  20 +import VChart from 'vue-echarts'
  21 +import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
  22 +import { use } from 'echarts/core'
  23 +import { CanvasRenderer } from 'echarts/renderers'
  24 +import { LineChart } from 'echarts/charts'
  25 +import config, { includes, seriesItem } from './config'
  26 +import { mergeTheme } from '@/packages/public/chart'
  27 +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
  28 +import { useChartDataFetch } from '@/hooks'
  29 +import { isPreview } from '@/utils'
  30 +import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
  31 +import isObject from 'lodash/isObject'
  32 +import dataJson from './data.json'
  33 +
  34 +const props = defineProps({
  35 + themeSetting: {
  36 + type: Object,
  37 + required: true
  38 + },
  39 + themeColor: {
  40 + type: Object,
  41 + required: true
  42 + },
  43 + chartConfig: {
  44 + type: Object as PropType<config>,
  45 + required: true
  46 + }
  47 +})
  48 +
  49 +const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
  50 +
  51 +use([DatasetComponent, CanvasRenderer, LineChart, GridComponent, TooltipComponent, LegendComponent])
  52 +
  53 +const replaceMergeArr = ref<string[]>()
  54 +
  55 +const option = computed(() => {
  56 + return mergeTheme(props.chartConfig.option, props.themeSetting, includes)
  57 +})
  58 +
  59 +// dataset 无法变更条数的补丁
  60 +watch(
  61 + () => props.chartConfig.option.dataset,
  62 + (newData: { dimensions: any }, oldData) => {
  63 + try {
  64 + if (!isObject(newData) || !('dimensions' in newData)) return
  65 + if (Array.isArray(newData?.dimensions)) {
  66 + const seriesArr = []
  67 + for (let i = 0; i < newData.dimensions.length - 1; i++) {
  68 + seriesArr.push(seriesItem)
  69 + }
  70 + replaceMergeArr.value = ['series']
  71 + props.chartConfig.option.series = seriesArr
  72 + nextTick(() => {
  73 + replaceMergeArr.value = []
  74 + })
  75 + }
  76 + } catch (error) {
  77 + console.log(error)
  78 + }
  79 + },
  80 + {
  81 + deep: false
  82 + }
  83 +)
  84 +
  85 +let seriesDataNum = -1
  86 +let seriesDataMaxLength = 0
  87 +let intervalInstance: any = null
  88 +const duration = 1500
  89 +
  90 +// 会重新选择需要选中和展示的数据
  91 +const handleSeriesData = () => {
  92 + if (seriesDataNum > -1) {
  93 + vChartRef.value?.dispatchAction({
  94 + type: 'downplay',
  95 + dataIndex: seriesDataNum
  96 + })
  97 + }
  98 + seriesDataNum = seriesDataNum >= seriesDataMaxLength - 1 ? 0 : seriesDataNum + 1
  99 + vChartRef.value?.dispatchAction({
  100 + type: 'showTip',
  101 + seriesIndex: 0,
  102 + dataIndex: seriesDataNum
  103 + })
  104 +}
  105 +
  106 +// 新增轮播
  107 +const addPieInterval = (newData?: typeof dataJson, skipPre = false) => {
  108 + if (!skipPre && !Array.isArray(newData?.source)) return
  109 + if (!skipPre) seriesDataMaxLength = newData?.source.length || 0
  110 + clearInterval(intervalInstance)
  111 + intervalInstance = setInterval(() => {
  112 + handleSeriesData()
  113 + }, duration)
  114 +}
  115 +
  116 +// 取消轮播
  117 +const clearPieInterval = () => {
  118 + vChartRef.value?.dispatchAction({
  119 + type: 'hideTip',
  120 + seriesIndex: 0,
  121 + dataIndex: seriesDataNum
  122 + })
  123 + vChartRef.value?.dispatchAction({
  124 + type: 'downplay',
  125 + dataIndex: seriesDataNum
  126 + })
  127 + clearInterval(intervalInstance)
  128 + intervalInstance = null
  129 +}
  130 +
  131 +// 处理鼠标聚焦高亮内容
  132 +const handleHighlight = () => {
  133 + clearPieInterval()
  134 +}
  135 +
  136 +// 处理鼠标取消悬浮
  137 +const handleDownplay = () => {
  138 + if (props.chartConfig.option.isCarousel && !intervalInstance) {
  139 + // 恢复轮播
  140 + addPieInterval(undefined, true)
  141 + }
  142 +}
  143 +
  144 +watch(
  145 + () => props.chartConfig.option.isCarousel,
  146 + newData => {
  147 + if (newData) {
  148 + addPieInterval(undefined, true)
  149 + props.chartConfig.option.legend.show = false
  150 + } else {
  151 + props.chartConfig.option.legend.show = true
  152 + clearPieInterval()
  153 + }
  154 + }
  155 +)
  156 +
  157 +const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore, (newData: typeof dataJson) => {
  158 + addPieInterval(newData)
  159 +})
  160 +
  161 +onMounted(() => {
  162 + seriesDataMaxLength = dataJson.source.length
  163 + if (props.chartConfig.option.isCarousel) {
  164 + addPieInterval(undefined, true)
  165 + }
  166 +})
  167 +</script>
... ...
  1 +import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public'
  2 +import { OverrideLineGradientsConfig } from './index'
  3 +import { CreateComponentType } from '@/packages/index.d'
  4 +import { graphic } from 'echarts/core'
  5 +import { defaultTheme, chartColorsSearch } from '@/settings/chartThemes/index'
  6 +import cloneDeep from 'lodash/cloneDeep'
  7 +import dataJson from './data.json'
  8 +
  9 +export const includes = ['legend', 'xAxis', 'yAxis', 'grid']
  10 +
  11 +// 其它配置项比如新增(动画)
  12 +const otherConfig = {
  13 + // 轮播动画
  14 + isCarousel: false,
  15 +}
  16 +const option = {
  17 + ...otherConfig,
  18 + tooltip: {
  19 + show: true,
  20 + trigger: 'axis',
  21 + axisPointer: {
  22 + type: 'line'
  23 + }
  24 + },
  25 + xAxis: {
  26 + show: true,
  27 + type: 'category'
  28 + },
  29 + yAxis: {
  30 + show: true,
  31 + type: 'value'
  32 + },
  33 + dataset: { ...dataJson },
  34 + series: [
  35 + {
  36 + type: 'line',
  37 + smooth: false,
  38 + symbolSize: 5, //设定实心点的大小
  39 + label: {
  40 + show: true,
  41 + position: 'top',
  42 + color: '#fff',
  43 + fontSize: 12
  44 + },
  45 + lineStyle: {
  46 + width: 3,
  47 + type: 'solid'
  48 + },
  49 + areaStyle: {
  50 + opacity: 0.8,
  51 + color: new graphic.LinearGradient(0, 0, 0, 1, [
  52 + {
  53 + offset: 0,
  54 + color: chartColorsSearch[defaultTheme][3]
  55 + },
  56 + {
  57 + offset: 1,
  58 + color: 'rgba(0,0,0,0)'
  59 + }
  60 + ])
  61 + }
  62 + },
  63 + {
  64 + type: 'line',
  65 + smooth: false,
  66 + label: {
  67 + show: true,
  68 + position: 'top',
  69 + color: '#fff',
  70 + fontSize: 12
  71 + },
  72 + lineStyle: {
  73 + width: 3,
  74 + type: 'solid'
  75 + },
  76 + areaStyle: {
  77 + opacity: 0.8,
  78 + color: new graphic.LinearGradient(0, 0, 0, 1, [
  79 + {
  80 + offset: 0,
  81 + color: chartColorsSearch[defaultTheme][4]
  82 + },
  83 + {
  84 + offset: 1,
  85 + color: 'rgba(0,0,0,0)'
  86 + }
  87 + ])
  88 + }
  89 + }
  90 + ]
  91 +}
  92 +
  93 +export default class Config extends PublicConfigClass implements CreateComponentType {
  94 + public key: string = OverrideLineGradientsConfig.key
  95 + public chartConfig = cloneDeep(OverrideLineGradientsConfig)
  96 + // 图表配置项
  97 + public option = echartOptionProfixHandle(option, includes)
  98 +}
... ...
  1 +<template>
  2 + <!-- Echarts 全局设置 -->
  3 + <global-setting :optionData="optionData"></global-setting>
  4 + <CollapseItem
  5 + v-for="(item, index) in seriesList"
  6 + :key="index"
  7 + name="单折线面积图"
  8 + :expanded="true"
  9 + >
  10 + <SettingItemBox name="线条">
  11 + <SettingItem name="宽度">
  12 + <n-input-number
  13 + v-model:value="item.lineStyle.width"
  14 + :min="1"
  15 + size="small"
  16 + placeholder="自动计算"
  17 + ></n-input-number>
  18 + </SettingItem>
  19 + <SettingItem name="类型">
  20 + <n-select
  21 + v-model:value="item.lineStyle.type"
  22 + size="small"
  23 + :options="lineConf.lineStyle.type"
  24 + ></n-select>
  25 + </SettingItem>
  26 + </SettingItemBox>
  27 + <SettingItemBox name="动画" :alone="true">
  28 + <SettingItem>
  29 + <n-space>
  30 + <n-switch v-model:value="optionData.isCarousel" size="small"></n-switch>
  31 + <n-text>开启<n-text :depth="3">(将自动隐藏图例)</n-text></n-text>
  32 + </n-space>
  33 + </SettingItem>
  34 + <SettingItem>
  35 + <n-text :depth="3">无鼠标点击图例场景时,可强行打开图例</n-text>
  36 + </SettingItem>
  37 + </SettingItemBox>
  38 + <SettingItemBox name="实心点">
  39 + <SettingItem name="大小">
  40 + <n-input-number
  41 + v-model:value="item.symbolSize"
  42 + :min="1"
  43 + :max="100"
  44 + size="small"
  45 + placeholder="自动计算"
  46 + ></n-input-number>
  47 + </SettingItem>
  48 + </SettingItemBox>
  49 + <setting-item-box name="标签">
  50 + <setting-item>
  51 + <n-space>
  52 + <n-switch v-model:value="item.label.show" size="small" />
  53 + <n-text>展示标签</n-text>
  54 + </n-space>
  55 + </setting-item>
  56 + <setting-item name="大小">
  57 + <n-input-number
  58 + v-model:value="item.label.fontSize"
  59 + size="small"
  60 + :min="1"
  61 + ></n-input-number>
  62 + </setting-item>
  63 + <setting-item name="颜色">
  64 + <n-color-picker
  65 + size="small"
  66 + :modes="['hex']"
  67 + v-model:value="item.label.color"
  68 + ></n-color-picker>
  69 + </setting-item>
  70 + <setting-item name="位置">
  71 + <n-select
  72 + v-model:value="item.label.position"
  73 + :options="[
  74 + { label: 'top', value: 'top' },
  75 + { label: 'left', value: 'left' },
  76 + { label: 'right', value: 'right' },
  77 + { label: 'bottom', value: 'bottom' },
  78 + ]"
  79 + />
  80 + </setting-item>
  81 + </setting-item-box>
  82 + </CollapseItem>
  83 +</template>
  84 +
  85 +<script setup lang="ts">
  86 +import { PropType, computed } from 'vue'
  87 +import { lineConf } from '@/packages/chartConfiguration/echarts/index'
  88 +import { GlobalThemeJsonType } from '@/settings/chartThemes/index'
  89 +import {
  90 + GlobalSetting,
  91 + CollapseItem,
  92 + SettingItemBox,
  93 + SettingItem
  94 +} from '@/components/Pages/ChartItemSetting'
  95 +
  96 +const props = defineProps({
  97 + optionData: {
  98 + type: Object as PropType<GlobalThemeJsonType>,
  99 + required: true
  100 + },
  101 +})
  102 +
  103 +const seriesList = computed(() => {
  104 + return props.optionData.series
  105 +})
  106 +</script>
... ...
  1 +{
  2 + "dimensions": ["product", "data1", "data2"],
  3 + "source": [
  4 + {
  5 + "product": "Mon",
  6 + "data1": 120,
  7 + "data2": 130
  8 + },
  9 + {
  10 + "product": "Tue",
  11 + "data1": 200,
  12 + "data2": 130
  13 + },
  14 + {
  15 + "product": "Wed",
  16 + "data1": 150,
  17 + "data2": 312
  18 + },
  19 + {
  20 + "product": "Thu",
  21 + "data1": 80,
  22 + "data2": 268
  23 + },
  24 + {
  25 + "product": "Fri",
  26 + "data1": 70,
  27 + "data2": 155
  28 + },
  29 + {
  30 + "product": "Sat",
  31 + "data1": 110,
  32 + "data2": 117
  33 + },
  34 + {
  35 + "product": "Sun",
  36 + "data1": 130,
  37 + "data2": 160
  38 + }
  39 + ]
  40 +}
... ...
  1 +import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
  2 +import { ChatCategoryEnum, ChatCategoryEnumName } from '@/packages/components/Charts/index.d'
  3 +import { useWidgetKey } from '@/packages/external/useWidgetKey'
  4 +
  5 +const { key, conKey, chartKey } = useWidgetKey('OverrideLineGradients', true)
  6 +
  7 +export const OverrideLineGradientsConfig: ConfigType = {
  8 + key,
  9 + chartKey,
  10 + conKey,
  11 + title: '双折线渐变面积图动画',
  12 + category: ChatCategoryEnum.LINE,
  13 + categoryName: ChatCategoryEnumName.LINE,
  14 + package: PackagesCategoryEnum.CHARTS,
  15 + chartFrame: ChartFrameEnum.ECHARTS,
  16 + image: 'line_gradient.png'
  17 +}
... ...
  1 +<template>
  2 + <v-chart
  3 + ref="vChartRef"
  4 + :init-options="initOptions"
  5 + :theme="themeColor"
  6 + :option="option.value"
  7 + :manual-update="isPreview()"
  8 + autoresize
  9 + @mouseover="handleHighlight"
  10 + @mouseout="handleDownplay"
  11 + ></v-chart>
  12 +</template>
  13 +
  14 +<script setup lang="ts">
  15 +import { reactive, watch, PropType,onMounted } from 'vue'
  16 +import VChart from 'vue-echarts'
  17 +import { useCanvasInitOptions } from '@/hooks/useCanvasInitOptions.hook'
  18 +import { use, graphic } from 'echarts/core'
  19 +import { CanvasRenderer } from 'echarts/renderers'
  20 +import { LineChart } from 'echarts/charts'
  21 +import config, { includes } from './config'
  22 +import { mergeTheme } from '@/packages/public/chart'
  23 +import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
  24 +import { chartColorsSearch, defaultTheme } from '@/settings/chartThemes/index'
  25 +import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
  26 +import { useChartDataFetch } from '@/hooks'
  27 +import { isPreview, colorGradientCustomMerge} from '@/utils'
  28 +import dataJson from './data.json'
  29 +
  30 +const props = defineProps({
  31 + themeSetting: {
  32 + type: Object,
  33 + required: true
  34 + },
  35 + themeColor: {
  36 + type: Object,
  37 + required: true
  38 + },
  39 + chartConfig: {
  40 + type: Object as PropType<config>,
  41 + required: true
  42 + }
  43 +})
  44 +
  45 +const initOptions = useCanvasInitOptions(props.chartConfig.option, props.themeSetting)
  46 +
  47 +use([DatasetComponent, CanvasRenderer, LineChart, GridComponent, TooltipComponent, LegendComponent])
  48 +const chartEditStore = useChartEditStore()
  49 +
  50 +const option = reactive({
  51 + value: {}
  52 +})
  53 +
  54 +// 渐变色处理
  55 +watch(
  56 + () => chartEditStore.getEditCanvasConfig.chartThemeColor,
  57 + (newColor: keyof typeof chartColorsSearch) => {
  58 + try {
  59 + if (!isPreview()) {
  60 + const themeColor =
  61 + colorGradientCustomMerge(chartEditStore.getEditCanvasConfig.chartCustomThemeColorInfo)[newColor] ||
  62 + colorGradientCustomMerge(chartEditStore.getEditCanvasConfig.chartCustomThemeColorInfo)[defaultTheme]
  63 + props.chartConfig.option.series.forEach((value: any, index: number) => {
  64 + value.areaStyle.color = new graphic.LinearGradient(0, 0, 0, 1, [
  65 + {
  66 + offset: 0,
  67 + color: themeColor[3 + index]
  68 + },
  69 + {
  70 + offset: 1,
  71 + color: 'rgba(0,0,0, 0)'
  72 + }
  73 + ])
  74 + })
  75 + }
  76 + option.value = mergeTheme(props.chartConfig.option, props.themeSetting, includes)
  77 + props.chartConfig.option = option.value
  78 + } catch (error) {
  79 + console.log(error)
  80 + }
  81 + },
  82 + {
  83 + immediate: true
  84 + }
  85 +)
  86 +
  87 +watch(
  88 + () => props.chartConfig.option.dataset,
  89 + () => {
  90 + option.value = props.chartConfig.option
  91 + }
  92 +)
  93 +let seriesDataNum = -1
  94 +let seriesDataMaxLength = 0
  95 +let intervalInstance: any = null
  96 +const duration = 1500
  97 +
  98 +// 会重新选择需要选中和展示的数据
  99 +const handleSeriesData = () => {
  100 + if (seriesDataNum > -1) {
  101 + vChartRef.value?.dispatchAction({
  102 + type: 'downplay',
  103 + dataIndex: seriesDataNum
  104 + })
  105 + }
  106 + seriesDataNum = seriesDataNum >= seriesDataMaxLength - 1 ? 0 : seriesDataNum + 1
  107 + vChartRef.value?.dispatchAction({
  108 + type: 'showTip',
  109 + seriesIndex: 0,
  110 + dataIndex: seriesDataNum
  111 + })
  112 +}
  113 +
  114 +// 新增轮播
  115 +const addPieInterval = (newData?: typeof dataJson, skipPre = false) => {
  116 + if (!skipPre && !Array.isArray(newData?.source)) return
  117 + if (!skipPre) seriesDataMaxLength = newData?.source.length || 0
  118 + clearInterval(intervalInstance)
  119 + intervalInstance = setInterval(() => {
  120 + handleSeriesData()
  121 + }, duration)
  122 +}
  123 +
  124 +// 取消轮播
  125 +const clearPieInterval = () => {
  126 + vChartRef.value?.dispatchAction({
  127 + type: 'hideTip',
  128 + seriesIndex: 0,
  129 + dataIndex: seriesDataNum
  130 + })
  131 + vChartRef.value?.dispatchAction({
  132 + type: 'downplay',
  133 + dataIndex: seriesDataNum
  134 + })
  135 + clearInterval(intervalInstance)
  136 + intervalInstance = null
  137 +}
  138 +
  139 +// 处理鼠标聚焦高亮内容
  140 +const handleHighlight = () => {
  141 + clearPieInterval()
  142 +}
  143 +
  144 +// 处理鼠标取消悬浮
  145 +const handleDownplay = () => {
  146 + if (props.chartConfig.option.isCarousel && !intervalInstance) {
  147 + // 恢复轮播
  148 + addPieInterval(undefined, true)
  149 + }
  150 +}
  151 +
  152 +watch(
  153 + () => props.chartConfig.option.isCarousel,
  154 + newData => {
  155 + if (newData) {
  156 + addPieInterval(undefined, true)
  157 + props.chartConfig.option.legend.show = false
  158 + } else {
  159 + props.chartConfig.option.legend.show = true
  160 + clearPieInterval()
  161 + }
  162 + }
  163 +)
  164 +
  165 +const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore, (newData: typeof dataJson) => {
  166 + addPieInterval(newData)
  167 +})
  168 +
  169 +onMounted(() => {
  170 + seriesDataMaxLength = dataJson.source.length
  171 + if (props.chartConfig.option.isCarousel) {
  172 + addPieInterval(undefined, true)
  173 + }
  174 +})
  175 +</script>
... ...
... ... @@ -9,6 +9,9 @@ import { OverrideSelectConfig } from '@/packages/components/external/Information
9 9 import { OverrideInputsDateConfig } from '@/packages/components/external/Informations/Mores/OverrideInputsDate'
10 10 import { OverrideInputsTabConfig } from '@/packages/components/external/Informations/Mores/OverrideInputsTab'
11 11 import { OverrideTextCommonConfig } from '@/packages/components/external/Informations/Mores/OverrideTextCommon'
  12 +import { OverrideBarCommonConfig } from '@/packages/components/external/Charts/Bars/OverrideBarCommon'
  13 +import { OverrideLineCommonConfig } from '@/packages/components/external/Charts/Lines/OverrideLineCommon'
  14 +import { OverrideLineGradientsConfig } from '@/packages/components/external/Charts/Lines/OverrideLineGradients'
12 15
13 16 export function useInjectLib(packagesList: EPackagesType) {
14 17
... ... @@ -22,6 +25,9 @@ export function useInjectLib(packagesList: EPackagesType) {
22 25 addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.INFORMATIONS, OverrideInputsDateConfig)
23 26 addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.INFORMATIONS, OverrideInputsTabConfig)
24 27 addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.INFORMATIONS, OverrideTextCommonConfig)
  28 + addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.CHARTS, OverrideBarCommonConfig)
  29 + addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.CHARTS, OverrideLineCommonConfig)
  30 + addWidgetToCategoryByCategoryName(packagesList, PackagesCategoryEnum.CHARTS, OverrideLineGradientsConfig)
25 31 }
26 32
27 33 /**
... ...