Эх сурвалжийг харах

feat: 初步添加词云组件

tnt group 3 жил өмнө
parent
commit
c4a7c673f8

+ 1 - 0
package.json

@@ -19,6 +19,7 @@
     "crypto-js": "^4.1.1",
     "echarts-liquidfill": "^3.1.0",
     "echarts-stat": "^1.2.0",
+    "echarts-wordcloud": "^2.0.0",
     "highlight.js": "^11.5.0",
     "html2canvas": "^1.4.1",
     "keymaster": "^1.6.2",

+ 13 - 0
pnpm-lock.yaml

@@ -25,6 +25,7 @@ specifiers:
   echarts: ^5.3.2
   echarts-liquidfill: ^3.1.0
   echarts-stat: ^1.2.0
+  echarts-wordcloud: ^2.0.0
   eslint: ^8.12.0
   eslint-config-prettier: ^8.5.0
   eslint-plugin-import: ^2.26.0
@@ -71,6 +72,7 @@ dependencies:
   crypto-js: 4.1.1
   echarts-liquidfill: 3.1.0_echarts@5.3.3
   echarts-stat: registry.npmmirror.com/echarts-stat/1.2.0
+  echarts-wordcloud: registry.npmmirror.com/echarts-wordcloud/2.0.0_echarts@5.3.3
   highlight.js: 11.5.1
   html2canvas: 1.4.1
   keymaster: 1.6.2
@@ -5396,6 +5398,17 @@ packages:
     version: 1.2.0
     dev: false
 
+  registry.npmmirror.com/echarts-wordcloud/2.0.0_echarts@5.3.3:
+    resolution: {integrity: sha512-K7l6pTklqdW7ZWzT/1CS0KhBSINr/cd7c5N1fVMzZMwLQHEwT7x+nivK7g5hkVh7WNcAv4Dn6/ZS5zMKRozC1g==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/echarts-wordcloud/-/echarts-wordcloud-2.0.0.tgz}
+    id: registry.npmmirror.com/echarts-wordcloud/2.0.0
+    name: echarts-wordcloud
+    version: 2.0.0
+    peerDependencies:
+      echarts: ^5.0.1
+    dependencies:
+      echarts: 5.3.3
+    dev: false
+
   registry.npmmirror.com/esbuild-android-64/0.14.43:
     resolution: {integrity: sha512-kqFXAS72K6cNrB6RiM7YJ5lNvmWRDSlpi7ZuRZ1hu1S3w0zlwcoCxWAyM23LQUyZSs1PbjHgdbbfYAN8IGh6xg==, registry: https://registry.npm.taobao.org/, tarball: https://registry.npmmirror.com/esbuild-android-64/-/esbuild-android-64-0.14.43.tgz}
     name: esbuild-android-64

+ 0 - 6
src/packages/components/Informations/Mores/TextCloud/config.vue

@@ -1,6 +0,0 @@
-<template>
-</template>
-
-<script setup lang="ts">
-
-</script>

+ 0 - 13
src/packages/components/Informations/Mores/TextCloud/index.vue

@@ -1,13 +0,0 @@
-<template>
-  <div>
-    词云
-  </div>
-</template>
-
-<script setup lang="ts">
-
-</script>
-
-<style lang="scss" scoped>
-
-</style>

+ 95 - 0
src/packages/components/Informations/Mores/WordCloud/config.ts

@@ -0,0 +1,95 @@
+import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public'
+import { WordCloudConfig } from './index'
+import { CreateComponentType } from '@/packages/index.d'
+import cloneDeep from 'lodash/cloneDeep'
+import dataJson from './data.json'
+
+export const includes = []
+
+export const ShapeEnumList = [
+  { label: '圆形', value: 'circle' },
+  { label: '心形', value: 'cardioid' },
+  { label: '钻石', value: 'diamond' },
+  { label: '右三角形', value: 'triangle-forward' },
+  { label: '三角形', value: 'triangle' },
+  { label: '五边形', value: 'pentagon' },
+  { label: '星星', value: 'star' }
+]
+
+export const option = {
+  dataset: [...dataJson],
+  tooltip: {},
+  series: [
+    {
+      type: 'wordCloud',
+
+      // “云”绘制的形状,可以是表示为回调函数,也可以是固定关键字。
+      // 可用值有:circle|cardioid|diamond|triangle-forward|triangle|pentagon|star
+      shape: 'circle',
+
+      // 白色区域将被排除在绘制文本之外的剪影图像。
+      // 随着云的形状生长,形状选项将继续应用。
+      // maskImage: maskImage,
+
+      // Folllowing left/top/width/height/right/bottom are used for positioning the word cloud
+      // Default to be put in the center and has 75% x 80% size.
+      left: 'center',
+      top: 'center',
+      width: '70%',
+      height: '80%',
+      right: null,
+      bottom: null,
+
+      // 文本大小范围,默认 [12,60]
+      sizeRange: [12, 60],
+
+      // 文本旋转范围和程度的步骤。 文本将通过旋转步骤45在[-90,90]中随机旋转
+      rotationRange: [0, 0],
+      rotationStep: 45,
+
+      // size of the grid in pixels for marking the availability of the canvas
+      // 网格大小越大,单词之间的差距就越大。
+      gridSize: 8,
+
+      // 设置为true,以允许单词在画布之外部分地绘制。允许绘制大于画布的大小
+      drawOutOfBound: false,
+
+      // If perform layout animation.
+      // NOTE disable it will lead to UI blocking when there is lots of words.
+      layoutAnimation: true,
+
+      // Global text style
+      textStyle: {
+        fontFamily: 'sans-serif',
+        fontWeight: 'bold'
+        // 颜色可以是回调功能或颜色字符串
+        // color: function () {
+        //   // 随机颜色
+        //   return (
+        //     'rgb(' +
+        //     [Math.round(Math.random() * 160), Math.round(Math.random() * 160), Math.round(Math.random() * 160)].join(
+        //       ','
+        //     ) +
+        //     ')'
+        //   )
+        // }
+      },
+      emphasis: {
+        focus: 'self',
+
+        textStyle: {
+          shadowBlur: 10,
+          shadowColor: '#333'
+        }
+      },
+      data: [...dataJson]
+    }
+  ]
+}
+
+export default class Config extends PublicConfigClass implements CreateComponentType {
+  public key = WordCloudConfig.key
+  public chartConfig = cloneDeep(WordCloudConfig)
+  // 图表配置项
+  public option = echartOptionProfixHandle(option, includes)
+}

+ 89 - 0
src/packages/components/Informations/Mores/WordCloud/config.vue

@@ -0,0 +1,89 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<!-- eslint-disable vue/no-mutating-props -->
+<template>
+  <collapse-item name="词云" expanded>
+    <setting-item-box name="形状">
+      <setting-item>
+        <n-select v-model:value="optionData.series[0].shape" size="small" :options="ShapeEnumList" />
+      </setting-item>
+      <setting-item>
+        <n-checkbox v-model:checked="optionData.series[0].drawOutOfBound" size="small">允许出边</n-checkbox>
+      </setting-item>
+    </setting-item-box>
+
+    <setting-item-box name="布局">
+      <setting-item name="宽度">
+        <n-slider
+          v-model:value="customProps.width"
+          :min="0"
+          :max="100"
+          :format-tooltip="sliderFormatTooltip"
+          @update:value="updateWidth"
+        ></n-slider>
+      </setting-item>
+      <setting-item name="高度">
+        <n-slider
+          v-model:value="customProps.height"
+          :min="0"
+          :max="100"
+          :format-tooltip="sliderFormatTooltip"
+          @update:value="updateHeight"
+        ></n-slider>
+      </setting-item>
+    </setting-item-box>
+
+    <setting-item-box name="样式" alone>
+      <setting-item name="字体区间(最小/最大字体)">
+        <n-slider v-model:value="optionData.series[0].sizeRange" range :step="1" :min="6" :max="100" />
+      </setting-item>
+      <setting-item name="旋转角度">
+        <n-slider
+          v-model:value="customProps.rotationStep"
+          :step="15"
+          :min="0"
+          :max="45"
+          @update:value="updateRotation"
+        />
+      </setting-item>
+    </setting-item-box>
+  </collapse-item>
+</template>
+
+<script setup lang="ts">
+import { PropType, reactive } from 'vue'
+import { option, ShapeEnumList } from './config'
+// eslint-disable-next-line no-unused-vars
+import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
+
+const props = defineProps({
+  optionData: {
+    type: Object as PropType<typeof option>,
+    required: true
+  }
+})
+
+const sliderFormatTooltip = (v: number) => {
+  return `${v}%`
+}
+
+const customProps = reactive({
+  width: 70,
+  height: 80,
+  rotationStep: 0 // 旋转步长
+})
+
+const updateWidth = (value: number) => {
+  // eslint-disable-next-line vue/no-mutating-props
+  props.optionData.series[0].width = `${value}%`
+}
+const updateHeight = (value: number) => {
+  // eslint-disable-next-line vue/no-mutating-props
+  props.optionData.series[0].height = `${value}%`
+}
+const updateRotation = (value: number) => {
+  // eslint-disable-next-line vue/no-mutating-props
+  props.optionData.series[0].rotationStep = value
+  // eslint-disable-next-line vue/no-mutating-props
+  props.optionData.series[0].rotationRange = value === 0 ? [0, 0] : [-90, 90]
+}
+</script>

+ 90 - 0
src/packages/components/Informations/Mores/WordCloud/data.json

@@ -0,0 +1,90 @@
+[
+  {
+    "name": "数据可视化",
+    "value": 8000,
+    "textStyle": {
+      "color": "#78fbb2"
+    },
+    "emphasis": {
+      "textStyle": {
+        "color": "red"
+      }
+    }
+  },
+  {
+    "name": "GO VIEW",
+    "value": 6181
+  },
+  {
+    "name": "低代码",
+    "value": 4386
+  },
+  {
+    "name": "Vue3",
+    "value": 4055
+  },
+  {
+    "name": "TypeScript4",
+    "value": 2467
+  },
+  {
+    "name": "Vite2",
+    "value": 2244
+  },
+  {
+    "name": "NaiveUI",
+    "value": 1898
+  },
+  {
+    "name": "ECharts5",
+    "value": 1484
+  },
+  {
+    "name": "Axios",
+    "value": 1112
+  },
+  {
+    "name": "Pinia2",
+    "value": 965
+  },
+  {
+    "name": "PlopJS",
+    "value": 847
+  },
+  {
+    "name": "sfc",
+    "value": 582
+  },
+  {
+    "name": "SCSS",
+    "value": 555
+  },
+  {
+    "name": "pnpm",
+    "value": 550
+  },
+  {
+    "name": "eslint",
+    "value": 462
+  },
+  {
+    "name": "json",
+    "value": 366
+  },
+  {
+    "name": "图表",
+    "value": 360
+  },
+  {
+    "name": "地图",
+    "value": 282
+  },
+  {
+    "name": "时钟",
+    "value": 273
+  },
+  {
+    "name": "标题",
+    "value": 265
+  }
+]

+ 5 - 5
src/packages/components/Informations/Mores/TextCloud/index.ts → src/packages/components/Informations/Mores/WordCloud/index.ts

@@ -1,11 +1,11 @@
 import image from '@/assets/images/chart/informations/words_cloud.png'
 import { ConfigType, PackagesCategoryEnum } from '@/packages/index.d'
-import { ChatCategoryEnum,ChatCategoryEnumName } from '../../index.d'
+import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
 
-export const TextCloudConfig: ConfigType = {
-  key: 'TextCloud',
-  chartKey: 'VTextCloud',
-  conKey: 'VCTextCloud',
+export const WordCloudConfig: ConfigType = {
+  key: 'WordCloud',
+  chartKey: 'VWordCloud',
+  conKey: 'VCWordCloud',
   title: '词云',
   category: ChatCategoryEnum.MORE,
   categoryName: ChatCategoryEnumName.MORE,

+ 63 - 0
src/packages/components/Informations/Mores/WordCloud/index.vue

@@ -0,0 +1,63 @@
+<!-- eslint-disable vue/multi-word-component-names -->
+<template>
+  <v-chart
+    ref="vChartRef"
+    :theme="themeColor"
+    :option="option"
+    :manual-update="isPreview()"
+    :update-options="{ replaceMerge: replaceMergeArr }"
+    autoresize
+  ></v-chart>
+</template>
+
+<script setup lang="ts">
+import { ref, computed, watch, PropType } from 'vue'
+import VChart from 'vue-echarts'
+import 'echarts-wordcloud'
+import { use } from 'echarts/core'
+import { CanvasRenderer } from 'echarts/renderers'
+import { BarChart } from 'echarts/charts'
+import config, { includes } from './config'
+import { mergeTheme } from '@/packages/public/chart'
+import { useChartDataFetch } from '@/hooks'
+import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
+import { isPreview } from '@/utils'
+import { DatasetComponent, GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
+
+const props = defineProps({
+  themeSetting: {
+    type: Object,
+    required: true
+  },
+  themeColor: {
+    type: Object,
+    required: true
+  },
+  chartConfig: {
+    type: Object as PropType<config>,
+    required: true
+  }
+})
+
+use([DatasetComponent, CanvasRenderer, BarChart, GridComponent, TooltipComponent, LegendComponent])
+
+const replaceMergeArr = ref<string[]>()
+
+const option = computed(() => {
+  return mergeTheme(props.chartConfig.option, props.themeSetting, includes)
+})
+
+// dataset 无法变更条数的补丁
+watch(
+  () => props.chartConfig.option.dataset,
+  newData => {
+    // eslint-disable-next-line vue/no-mutating-props
+    props.chartConfig.option.series[0].data = newData
+  },
+  {
+    deep: false
+  }
+)
+
+const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore)
+</script>

+ 2 - 2
src/packages/components/Informations/Mores/index.ts

@@ -1,4 +1,4 @@
-import { TextCloudConfig } from './TextCloud/index'
 import { ImageConfig } from './Image/index'
+import { WordCloudConfig } from './WordCloud/index'
 
-export default [ImageConfig, TextCloudConfig]
+export default [ImageConfig, WordCloudConfig]