Commit a2689a1cb7152a0a5e8e093b72387715dace63ab

Authored by fengwotao
1 parent fea8adbf

pref:移除了之前添加的所有动画组件

Showing 45 changed files with 376 additions and 2050 deletions
  1 +import { defHttp } from '@/utils/external/http/axios';
  2 +import {
  3 + ContentParams,
  4 + LoginResultModel,
  5 +} from './model/userModel';
  6 +
  7 +import type { ErrorMessageMode } from '/#/external/axios';
  8 +
  9 +enum Api {
  10 + CONTENT = '/data_view/content',
  11 +}
  12 +
  13 +/**
  14 + * @description: content save api
  15 + */
  16 +export function contentSaveApi(params: ContentParams, mode: ErrorMessageMode = 'modal') {
  17 + return defHttp.post<LoginResultModel>(
  18 + {
  19 + url: Api.CONTENT,
  20 + params,
  21 + },
  22 + {
  23 + errorMessageMode: mode,
  24 + }
  25 + );
  26 +}
... ...
  1 +/**
  2 + * @description: Login interface parameters
  3 + */
  4 +export interface ContentParams{
  5 + "content": string,
  6 + "createTime": string,
  7 + "creator": string,
  8 + "defaultConfig": string,
  9 + "description": string,
  10 + "enabled": boolean,
  11 + "icon": string,
  12 + "id": string,
  13 + "name": string,
  14 + "nodeIds": [
  15 + string
  16 + ],
  17 + "remark": string,
  18 + "roleIds": [
  19 + string
  20 + ],
  21 + "tenantExpireTime": string,
  22 + "tenantId": string,
  23 + "tenantProfileId": string,
  24 + "tenantStatus": string,
  25 + "updateTime":string,
  26 + "updater":string,
  27 + "viewId":string
  28 +}
  29 +export interface RoleInfo {
  30 + roleName: string;
  31 + value: string;
  32 +}
  33 +
  34 +/**
  35 + * @description: Login interface return value
  36 + */
  37 +export interface LoginResultModel {{
  38 + "content": string,
  39 + "createTime": string,
  40 + "creator": string,
  41 + "defaultConfig": string,
  42 + "description": string,
  43 + "enabled": boolean,
  44 + "icon": string,
  45 + "id": string,
  46 + "name": string,
  47 + "nodeIds": [
  48 + string
  49 + ],
  50 + "remark": string,
  51 + "roleIds": [
  52 + string
  53 + ],
  54 + "tenantExpireTime": string,
  55 + "tenantId": string,
  56 + "tenantProfileId": string,
  57 + "tenantStatus": string,
  58 + "updateTime":string,
  59 + "updater":string,
  60 + "viewId":string
  61 +}
  62 +
... ...
1   -import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public'
2   -import { WordCloudConfig } 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 = []
8   -
9   -export const ShapeEnumList = [
10   - { label: '圆形', value: 'circle' },
11   - { label: '心形', value: 'cardioid' },
12   - { label: '钻石', value: 'diamond' },
13   - { label: '右三角形', value: 'triangle-forward' },
14   - { label: '三角形', value: 'triangle' },
15   - { label: '五边形', value: 'pentagon' },
16   - { label: '星星', value: 'star' }
17   -]
18   -
19   -export const option = {
20   - dataset: [...dataJson],
21   - tooltip: {},
22   - series: [
23   - {
24   - type: 'wordCloud',
25   -
26   - // “云”绘制的形状,可以是表示为回调函数,也可以是固定关键字。
27   - // 可用值有:circle|cardioid|diamond|triangle-forward|triangle|pentagon|star
28   - shape: 'circle',
29   -
30   - // 白色区域将被排除在绘制文本之外的剪影图像。
31   - // 随着云的形状生长,形状选项将继续应用。
32   - // maskImage: maskImage,
33   -
34   - // Folllowing left/top/width/height/right/bottom are used for positioning the word cloud
35   - // Default to be put in the center and has 75% x 80% size.
36   - left: 'center',
37   - top: 'center',
38   - width: '70%',
39   - height: '80%',
40   - right: null,
41   - bottom: null,
42   -
43   - // 文本大小范围,默认 [12,60]
44   - sizeRange: [12, 60],
45   -
46   - // 文本旋转范围和程度的步骤。 文本将通过旋转步骤45在[-90,90]中随机旋转
47   - rotationRange: [0, 0],
48   - rotationStep: 0,
49   -
50   - // size of the grid in pixels for marking the availability of the canvas
51   - // 网格大小越大,单词之间的差距就越大。
52   - gridSize: 8,
53   -
54   - // 设置为true,以允许单词在画布之外部分地绘制。允许绘制大于画布的大小
55   - drawOutOfBound: false,
56   -
57   - // If perform layout animation.
58   - // NOTE disable it will lead to UI blocking when there is lots of words.
59   - layoutAnimation: true,
60   -
61   - // Global text style
62   - textStyle: {
63   - fontFamily: 'sans-serif',
64   - fontWeight: 'bold'
65   - // 颜色可以是回调功能或颜色字符串
66   - // color: function () {
67   - // // 随机颜色
68   - // return (
69   - // 'rgb(' +
70   - // [Math.round(Math.random() * 160), Math.round(Math.random() * 160), Math.round(Math.random() * 160)].join(
71   - // ','
72   - // ) +
73   - // ')'
74   - // )
75   - // }
76   - },
77   - emphasis: {
78   - focus: 'self',
79   -
80   - textStyle: {
81   - shadowBlur: 10,
82   - shadowColor: '#333'
83   - }
84   - },
85   - data: [...dataJson]
86   - }
87   - ]
88   -}
89   -
90   -export default class Config extends PublicConfigClass implements CreateComponentType {
91   - public key = WordCloudConfig.key
92   - public chartConfig = cloneDeep(WordCloudConfig)
93   - // 图表配置项
94   - public option = echartOptionProfixHandle(option, includes)
95   -}
1   -<template>
2   - <collapse-item name="词云" expanded>
3   - <setting-item-box name="形状">
4   - <setting-item>
5   - <n-select v-model:value="optionData.series[0].shape" size="small" :options="ShapeEnumList" />
6   - </setting-item>
7   - <setting-item>
8   - <n-checkbox v-model:checked="optionData.series[0].drawOutOfBound" size="small">允许出边</n-checkbox>
9   - </setting-item>
10   - </setting-item-box>
11   -
12   - <setting-item-box name="布局">
13   - <setting-item name="宽度">
14   - <n-slider
15   - v-model:value="series.width"
16   - :min="0"
17   - :max="100"
18   - :format-tooltip="sliderFormatTooltip"
19   - @update:value="updateWidth"
20   - ></n-slider>
21   - </setting-item>
22   - <setting-item name="高度">
23   - <n-slider
24   - v-model:value="series.height"
25   - :min="0"
26   - :max="100"
27   - :format-tooltip="sliderFormatTooltip"
28   - @update:value="updateHeight"
29   - ></n-slider>
30   - </setting-item>
31   - </setting-item-box>
32   -
33   - <setting-item-box name="样式" alone>
34   - <setting-item name="字体区间(最小/最大字体)">
35   - <n-slider v-model:value="optionData.series[0].sizeRange" range :step="1" :min="6" :max="100" />
36   - </setting-item>
37   - <setting-item name="旋转角度">
38   - <n-slider v-model:value="series.rotationStep" :step="15" :min="0" :max="45" @update:value="updateRotation" />
39   - </setting-item>
40   - </setting-item-box>
41   - </collapse-item>
42   -</template>
43   -
44   -<script setup lang="ts">
45   -import { PropType, computed } from 'vue'
46   -import { option, ShapeEnumList } from './config'
47   -// eslint-disable-next-line no-unused-vars
48   -import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
49   -
50   -const props = defineProps({
51   - optionData: {
52   - type: Object as PropType<typeof option>,
53   - required: true
54   - }
55   -})
56   -
57   -const series = computed(() => {
58   - const { width, height, rotationStep } = props.optionData.series[0]
59   - return {
60   - width: +width.replace('%', ''),
61   - height: +height.replace('%', ''),
62   - rotationStep
63   - }
64   -})
65   -
66   -const sliderFormatTooltip = (v: number) => {
67   - return `${v}%`
68   -}
69   -
70   -const updateWidth = (value: number) => {
71   - props.optionData.series[0].width = `${value}%`
72   -}
73   -
74   -const updateHeight = (value: number) => {
75   - props.optionData.series[0].height = `${value}%`
76   -}
77   -
78   -const updateRotation = (value: number) => {
79   - props.optionData.series[0].rotationStep = value
80   - props.optionData.series[0].rotationRange = value === 0 ? [0, 0] : [-90, 90]
81   -}
82   -</script>
1   -[
2   - {
3   - "name": "数据可视化",
4   - "value": 8000,
5   - "textStyle": {
6   - "color": "#78fbb2"
7   - },
8   - "emphasis": {
9   - "textStyle": {
10   - "color": "red"
11   - }
12   - }
13   - },
14   - {
15   - "name": "GO VIEW",
16   - "value": 6181
17   - },
18   - {
19   - "name": "低代码",
20   - "value": 4386
21   - },
22   - {
23   - "name": "Vue3",
24   - "value": 4055
25   - },
26   - {
27   - "name": "TypeScript4",
28   - "value": 2467
29   - },
30   - {
31   - "name": "Vite2",
32   - "value": 2244
33   - },
34   - {
35   - "name": "NaiveUI",
36   - "value": 1898
37   - },
38   - {
39   - "name": "ECharts5",
40   - "value": 1484
41   - },
42   - {
43   - "name": "Axios",
44   - "value": 1112
45   - },
46   - {
47   - "name": "Pinia2",
48   - "value": 965
49   - },
50   - {
51   - "name": "PlopJS",
52   - "value": 847
53   - },
54   - {
55   - "name": "sfc",
56   - "value": 582
57   - },
58   - {
59   - "name": "SCSS",
60   - "value": 555
61   - },
62   - {
63   - "name": "pnpm",
64   - "value": 550
65   - },
66   - {
67   - "name": "eslint",
68   - "value": 462
69   - },
70   - {
71   - "name": "json",
72   - "value": 366
73   - },
74   - {
75   - "name": "图表",
76   - "value": 360
77   - },
78   - {
79   - "name": "地图",
80   - "value": 282
81   - },
82   - {
83   - "name": "时钟",
84   - "value": 273
85   - },
86   - {
87   - "name": "标题",
88   - "value": 265
89   - }
90   -]
1   -import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
2   -import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
3   -
4   -export const WordCloudConfig: ConfigType = {
5   - key: 'WordCloud',
6   - chartKey: 'VWordCloud',
7   - conKey: 'VCWordCloud',
8   - title: '词云',
9   - category: ChatCategoryEnum.MORE,
10   - categoryName: ChatCategoryEnumName.MORE,
11   - package: PackagesCategoryEnum.INFORMATIONS,
12   - chartFrame: ChartFrameEnum.COMMON,
13   - image: 'words_cloud.png'
14   -}
1   -<template>
2   - <v-chart
3   - ref="vChartRef"
4   - :theme="themeColor"
5   - :option="option"
6   - :manual-update="isPreview()"
7   - :update-options="{ replaceMerge: replaceMergeArr }"
8   - autoresize
9   - ></v-chart>
10   -</template>
11   -
12   -<script setup lang="ts">
13   -import { ref, computed, watch, PropType } from 'vue'
14   -import VChart from 'vue-echarts'
15   -import 'echarts-wordcloud'
16   -import { use } from 'echarts/core'
17   -import { CanvasRenderer } from 'echarts/renderers'
18   -import config, { includes } from './config'
19   -import { mergeTheme, setOption } from '@/packages/public/chart'
20   -import { useChartDataFetch } from '@/hooks'
21   -import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
22   -import { isPreview } from '@/utils'
23   -import { GridComponent, TooltipComponent } from 'echarts/components'
24   -import dataJson from './data.json'
25   -
26   -const props = defineProps({
27   - themeSetting: {
28   - type: Object,
29   - required: true
30   - },
31   - themeColor: {
32   - type: Object,
33   - required: true
34   - },
35   - chartConfig: {
36   - type: Object as PropType<config>,
37   - required: true
38   - }
39   -})
40   -
41   -use([CanvasRenderer, GridComponent, TooltipComponent])
42   -
43   -const replaceMergeArr = ref<string[]>()
44   -
45   -const option = computed(() => {
46   - return mergeTheme(props.chartConfig.option, props.themeSetting, includes)
47   -})
48   -
49   -const dataSetHandle = (dataset: typeof dataJson) => {
50   - try {
51   - dataset && (props.chartConfig.option.series[0].data = dataset)
52   - vChartRef.value && isPreview() && setOption(vChartRef.value, props.chartConfig.option)
53   - } catch (error) {
54   - console.log(error)
55   - }
56   -}
57   -
58   -// dataset 无法变更条数的补丁
59   -watch(
60   - () => props.chartConfig.option.dataset,
61   - newData => {
62   - dataSetHandle(newData)
63   - },
64   - {
65   - deep: false
66   - }
67   -)
68   -
69   -const { vChartRef } = useChartDataFetch(props.chartConfig, useChartEditStore, (newData: typeof dataJson) => {
70   - dataSetHandle(newData)
71   -})
72   -</script>
1   -import {WordCloudConfig} from './WordCloud/index'
2   -
3   -export default [WordCloudConfig]
1   -// eslint-disable-next-line @typescript-eslint/ban-ts-comment
2   -// @ts-nocheck
3   -import {
4   - ArcCurve,
5   - BufferAttribute,
6   - BufferGeometry,
7   - Color,
8   - Line,
9   - LineBasicMaterial,
10   - Points,
11   - PointsMaterial,
12   - Quaternion,
13   - Vector3
14   -} from 'three'
15   -import { lon2xyz } from './common'
16   -
17   -/*
18   - * 绘制一条圆弧飞线
19   - * 5个参数含义:( 飞线圆弧轨迹半径, 开始角度, 结束角度)
20   - */
21   -function createFlyLine(radius, startAngle, endAngle, color) {
22   - const geometry = new BufferGeometry() //声明一个几何体对象BufferGeometry
23   - // ArcCurve创建圆弧曲线
24   - const arc = new ArcCurve(0, 0, radius, startAngle, endAngle, false)
25   - //getSpacedPoints是基类Curve的方法,返回一个vector2对象作为元素组成的数组
26   - const pointsArr = arc.getSpacedPoints(100) //分段数80,返回81个顶点
27   - geometry.setFromPoints(pointsArr) // setFromPoints方法从pointsArr中提取数据改变几何体的顶点属性vertices
28   - // 每个顶点对应一个百分比数据attributes.percent 用于控制点的渲染大小
29   - const percentArr = [] //attributes.percent的数据
30   - for (let i = 0; i < pointsArr.length; i++) {
31   - percentArr.push(i / pointsArr.length)
32   - }
33   - const percentAttribue = new BufferAttribute(new Float32Array(percentArr), 1)
34   - // 通过顶点数据percent点模型从大到小变化,产生小蝌蚪形状飞线
35   - geometry.attributes.percent = percentAttribue
36   - // 批量计算所有顶点颜色数据
37   - const colorArr = []
38   - for (let i = 0; i < pointsArr.length; i++) {
39   - const color1 = new Color(0xec8f43) //轨迹线颜色 青色
40   - const color2 = new Color(0xf3ae76) //黄色
41   - const color = color1.lerp(color2, i / pointsArr.length)
42   - colorArr.push(color.r, color.g, color.b)
43   - }
44   - // 设置几何体顶点颜色数据
45   - geometry.attributes.color = new BufferAttribute(new Float32Array(colorArr), 3)
46   - const size = 1.3
47   - // 点模型渲染几何体每个顶点
48   - const material = new PointsMaterial({
49   - size, //点大小
50   - // vertexColors: VertexColors, //使用顶点颜色渲染
51   - transparent: true,
52   - depthWrite: false
53   - })
54   - // 修改点材质的着色器源码(注意:不同版本细节可能会稍微会有区别,不过整体思路是一样的)
55   - material.onBeforeCompile = function (shader) {
56   - // 顶点着色器中声明一个attribute变量:百分比
57   - shader.vertexShader = shader.vertexShader.replace(
58   - 'void main() {',
59   - [
60   - 'attribute float percent;', //顶点大小百分比变量,控制点渲染大小
61   - 'void main() {'
62   - ].join('\n') // .join()把数组元素合成字符串
63   - )
64   - // 调整点渲染大小计算方式
65   - shader.vertexShader = shader.vertexShader.replace(
66   - 'gl_PointSize = size;',
67   - ['gl_PointSize = percent * size;'].join('\n') // .join()把数组元素合成字符串
68   - )
69   - }
70   - const FlyLine = new Points(geometry, material)
71   - material.color = new Color(color)
72   - FlyLine.name = '飞行线'
73   -
74   - return FlyLine
75   -}
76   -
77   -/**输入地球上任意两点的经纬度坐标,通过函数flyArc可以绘制一个飞线圆弧轨迹
78   - * lon1,lat1:轨迹线起点经纬度坐标
79   - * lon2,lat2:轨迹线结束点经纬度坐标
80   - */
81   -function flyArc(radius, lon1, lat1, lon2, lat2, options) {
82   - const sphereCoord1 = lon2xyz(radius, lon1, lat1) //经纬度坐标转球面坐标
83   - // startSphereCoord:轨迹线起点球面坐标
84   - const startSphereCoord = new Vector3(sphereCoord1.x, sphereCoord1.y, sphereCoord1.z)
85   - const sphereCoord2 = lon2xyz(radius, lon2, lat2)
86   - // startSphereCoord:轨迹线结束点球面坐标
87   - const endSphereCoord = new Vector3(sphereCoord2.x, sphereCoord2.y, sphereCoord2.z)
88   -
89   - //计算绘制圆弧需要的关于y轴对称的起点、结束点和旋转四元数
90   - const startEndQua = _3Dto2D(startSphereCoord, endSphereCoord)
91   - // 调用arcXOY函数绘制一条圆弧飞线轨迹
92   - const arcline = arcXOY(radius, startEndQua.startPoint, startEndQua.endPoint, options)
93   - arcline.quaternion.multiply(startEndQua.quaternion)
94   - return arcline
95   -}
96   -/*
97   - * 把3D球面上任意的两个飞线起点和结束点绕球心旋转到到XOY平面上,
98   - * 同时保持关于y轴对称,借助旋转得到的新起点和新结束点绘制
99   - * 一个圆弧,最后把绘制的圆弧反向旋转到原来的起点和结束点即可
100   - */
101   -function _3Dto2D(startSphere, endSphere) {
102   - /*计算第一次旋转的四元数:表示从一个平面如何旋转到另一个平面*/
103   - const origin = new Vector3(0, 0, 0) //球心坐标
104   - const startDir = startSphere.clone().sub(origin) //飞线起点与球心构成方向向量
105   - const endDir = endSphere.clone().sub(origin) //飞线结束点与球心构成方向向量
106   - // dir1和dir2构成一个三角形,.cross()叉乘计算该三角形法线normal
107   - const normal = startDir.clone().cross(endDir).normalize()
108   - const xoyNormal = new Vector3(0, 0, 1) //XOY平面的法线
109   - //.setFromUnitVectors()计算从normal向量旋转达到xoyNormal向量所需要的四元数
110   - // quaternion表示把球面飞线旋转到XOY平面上需要的四元数
111   - const quaternion3D_XOY = new Quaternion().setFromUnitVectors(normal, xoyNormal)
112   - /*第一次旋转:飞线起点、结束点从3D空间第一次旋转到XOY平面*/
113   - const startSphereXOY = startSphere.clone().applyQuaternion(quaternion3D_XOY)
114   - const endSphereXOY = endSphere.clone().applyQuaternion(quaternion3D_XOY)
115   -
116   - /*计算第二次旋转的四元数*/
117   - // middleV3:startSphereXOY和endSphereXOY的中点
118   - const middleV3 = startSphereXOY.clone().add(endSphereXOY).multiplyScalar(0.5)
119   - const midDir = middleV3.clone().sub(origin).normalize() // 旋转前向量midDir,中点middleV3和球心构成的方向向量
120   - const yDir = new Vector3(0, 1, 0) // 旋转后向量yDir,即y轴
121   - // .setFromUnitVectors()计算从midDir向量旋转达到yDir向量所需要的四元数
122   - // quaternion2表示让第一次旋转到XOY平面的起点和结束点关于y轴对称需要的四元数
123   - const quaternionXOY_Y = new Quaternion().setFromUnitVectors(midDir, yDir)
124   -
125   - /*第二次旋转:使旋转到XOY平面的点再次旋转,实现关于Y轴对称*/
126   - const startSpherXOY_Y = startSphereXOY.clone().applyQuaternion(quaternionXOY_Y)
127   - const endSphereXOY_Y = endSphereXOY.clone().applyQuaternion(quaternionXOY_Y)
128   -
129   - /**一个四元数表示一个旋转过程
130   - *.invert()方法表示四元数的逆,简单说就是把旋转过程倒过来
131   - * 两次旋转的四元数执行.invert()求逆,然后执行.multiply()相乘
132   - *新版本.invert()对应旧版本.invert()
133   - */
134   - const quaternionInverse = quaternion3D_XOY.clone().invert().multiply(quaternionXOY_Y.clone().invert())
135   - return {
136   - // 返回两次旋转四元数的逆四元数
137   - quaternion: quaternionInverse,
138   - // 范围两次旋转后在XOY平面上关于y轴对称的圆弧起点和结束点坐标
139   - startPoint: startSpherXOY_Y,
140   - endPoint: endSphereXOY_Y
141   - }
142   -}
143   -/**通过函数arcXOY()可以在XOY平面上绘制一个关于y轴对称的圆弧曲线
144   - * startPoint, endPoint:表示圆弧曲线的起点和结束点坐标值,起点和结束点关于y轴对称
145   - * 同时在圆弧轨迹的基础上绘制一段飞线*/
146   -function arcXOY(radius, startPoint, endPoint, options) {
147   - // 计算两点的中点
148   - const middleV3 = new Vector3().addVectors(startPoint, endPoint).multiplyScalar(0.5)
149   - // 弦垂线的方向dir(弦的中点和圆心构成的向量)
150   - const dir = middleV3.clone().normalize()
151   - // 计算球面飞线的起点、结束点和球心构成夹角的弧度值
152   - const earthRadianAngle = radianAOB(startPoint, endPoint, new Vector3(0, 0, 0))
153   - /*设置飞线轨迹圆弧的中间点坐标
154   - 弧度值 * radius * 0.2:表示飞线轨迹圆弧顶部距离地球球面的距离
155   - 起点、结束点相聚越远,构成的弧线顶部距离球面越高*/
156   - const arcTopCoord = dir.multiplyScalar(radius + earthRadianAngle * radius * 0.2) // 黄色飞行线的高度
157   - //求三个点的外接圆圆心(飞线圆弧轨迹的圆心坐标)
158   - const flyArcCenter = threePointCenter(startPoint, endPoint, arcTopCoord)
159   - // 飞线圆弧轨迹半径flyArcR
160   - const flyArcR = Math.abs(flyArcCenter.y - arcTopCoord.y)
161   - /*坐标原点和飞线起点构成直线和y轴负半轴夹角弧度值
162   - 参数分别是:飞线圆弧起点、y轴负半轴上一点、飞线圆弧圆心*/
163   - const flyRadianAngle = radianAOB(startPoint, new Vector3(0, -1, 0), flyArcCenter)
164   - const startAngle = -Math.PI / 2 + flyRadianAngle //飞线圆弧开始角度
165   - const endAngle = Math.PI - startAngle //飞线圆弧结束角度
166   - // 调用圆弧线模型的绘制函数
167   - const arcline = circleLine(flyArcCenter.x, flyArcCenter.y, flyArcR, startAngle, endAngle, options.color)
168   - // const arcline = new Group();// 不绘制轨迹线,使用 Group替换circleLine()即可
169   - arcline.center = flyArcCenter //飞线圆弧自定一个属性表示飞线圆弧的圆心
170   - arcline.topCoord = arcTopCoord //飞线圆弧自定一个属性表示飞线圆弧中间也就是顶部坐标
171   -
172   - // const flyAngle = Math.PI/ 10; //飞线圆弧固定弧度
173   - const flyAngle = (endAngle - startAngle) / 7 //飞线圆弧的弧度和轨迹线弧度相关
174   - // 绘制一段飞线,圆心做坐标原点
175   - const flyLine = createFlyLine(flyArcR, startAngle, startAngle + flyAngle, options.flyLineColor)
176   - flyLine.position.y = flyArcCenter.y //平移飞线圆弧和飞线轨迹圆弧重合
177   - //飞线段flyLine作为飞线轨迹arcLine子对象,继承飞线轨迹平移旋转等变换
178   - arcline.add(flyLine)
179   - //飞线段运动范围startAngle~flyEndAngle
180   - flyLine.flyEndAngle = endAngle - startAngle - flyAngle
181   - flyLine.startAngle = startAngle
182   - // arcline.flyEndAngle:飞线段当前角度位置,这里设置了一个随机值用于演示
183   - flyLine.AngleZ = arcline.flyEndAngle * Math.random()
184   - // flyLine.rotation.z = arcline.AngleZ;
185   - // arcline.flyLine指向飞线段,便于设置动画是访问飞线段
186   - arcline.userData['flyLine'] = flyLine
187   -
188   - return arcline
189   -}
190   -/*计算球面上两点和球心构成夹角的弧度值
191   -参数point1, point2:表示地球球面上两点坐标Vector3
192   -计算A、B两点和顶点O构成的AOB夹角弧度值*/
193   -function radianAOB(A, B, O) {
194   - // dir1、dir2:球面上两个点和球心构成的方向向量
195   - const dir1 = A.clone().sub(O).normalize()
196   - const dir2 = B.clone().sub(O).normalize()
197   - //点乘.dot()计算夹角余弦值
198   - const cosAngle = dir1.clone().dot(dir2)
199   - const radianAngle = Math.acos(cosAngle) //余弦值转夹角弧度值,通过余弦值可以计算夹角范围是0~180度
200   - return radianAngle
201   -}
202   -/*绘制一条圆弧曲线模型Line
203   -5个参数含义:(圆心横坐标, 圆心纵坐标, 飞线圆弧轨迹半径, 开始角度, 结束角度)*/
204   -function circleLine(x, y, r, startAngle, endAngle, color) {
205   - const geometry = new BufferGeometry() //声明一个几何体对象Geometry
206   - // ArcCurve创建圆弧曲线
207   - const arc = new ArcCurve(x, y, r, startAngle, endAngle, false)
208   - //getSpacedPoints是基类Curve的方法,返回一个vector2对象作为元素组成的数组
209   - const points = arc.getSpacedPoints(80) //分段数50,返回51个顶点
210   - geometry.setFromPoints(points) // setFromPoints方法从points中提取数据改变几何体的顶点属性vertices
211   - const material = new LineBasicMaterial({
212   - color: color || 0xd18547
213   - }) //线条材质
214   - const line = new Line(geometry, material) //线条模型对象
215   - return line
216   -}
217   -//求三个点的外接圆圆心,p1, p2, p3表示三个点的坐标Vector3。
218   -function threePointCenter(p1, p2, p3) {
219   - const L1 = p1.lengthSq() //p1到坐标原点距离的平方
220   - const L2 = p2.lengthSq()
221   - const L3 = p3.lengthSq()
222   - const x1 = p1.x,
223   - y1 = p1.y,
224   - x2 = p2.x,
225   - y2 = p2.y,
226   - x3 = p3.x,
227   - y3 = p3.y
228   - const S = x1 * y2 + x2 * y3 + x3 * y1 - x1 * y3 - x2 * y1 - x3 * y2
229   - const x = (L2 * y3 + L1 * y2 + L3 * y1 - L2 * y1 - L3 * y2 - L1 * y3) / S / 2
230   - const y = (L3 * x2 + L2 * x1 + L1 * x3 - L1 * x2 - L2 * x3 - L3 * x1) / S / 2
231   - // 三点外接圆圆心坐标
232   - const center = new Vector3(x, y, 0)
233   - return center
234   -}
235   -
236   -export { arcXOY, flyArc }
1   -import {
2   - CatmullRomCurve3,
3   - DoubleSide,
4   - Group,
5   - Mesh,
6   - MeshBasicMaterial,
7   - PlaneGeometry,
8   - Texture,
9   - TubeGeometry,
10   - Vector3
11   -} from 'three'
12   -import { punctuation } from '../world/Earth'
13   -
14   -/**
15   - * 经纬度坐标转球面坐标
16   - * @param {地球半径} R
17   - * @param {经度(角度值)} longitude
18   - * @param {维度(角度值)} latitude
19   - */
20   -export const lon2xyz = (R: number, longitude: number, latitude: number): Vector3 => {
21   - let lon = (longitude * Math.PI) / 180 // 转弧度值
22   - const lat = (latitude * Math.PI) / 180 // 转弧度值
23   - lon = -lon // js坐标系z坐标轴对应经度-90度,而不是90度
24   -
25   - // 经纬度坐标转球面坐标计算公式
26   - const x = R * Math.cos(lat) * Math.cos(lon)
27   - const y = R * Math.sin(lat)
28   - const z = R * Math.cos(lat) * Math.sin(lon)
29   - // 返回球面坐标
30   - return new Vector3(x, y, z)
31   -}
32   -
33   -// 创建波动光圈
34   -export const createWaveMesh = (options: { radius: number; lon: number; lat: number; textures: any }) => {
35   - const geometry = new PlaneGeometry(1, 1) //默认在XOY平面上
36   - const texture = options.textures.aperture
37   -
38   - const material = new MeshBasicMaterial({
39   - color: 0xe99f68,
40   - map: texture,
41   - transparent: true, //使用背景透明的png贴图,注意开启透明计算
42   - opacity: 1.0,
43   - depthWrite: false //禁止写入深度缓冲区数据
44   - })
45   - const mesh = new Mesh(geometry, material)
46   - // 经纬度转球面坐标
47   - const coord = lon2xyz(options.radius * 1.001, options.lon, options.lat)
48   - const size = options.radius * 0.12 //矩形平面Mesh的尺寸
49   - mesh.scale.set(size, size, size) //设置mesh大小
50   - mesh.userData['size'] = size //自顶一个属性,表示mesh静态大小
51   - mesh.userData['scale'] = Math.random() * 1.0 //自定义属性._s表示mesh在原始大小基础上放大倍数 光圈在原来mesh.size基础上1~2倍之间变化
52   - mesh.position.set(coord.x, coord.y, coord.z)
53   - const coordVec3 = new Vector3(coord.x, coord.y, coord.z).normalize()
54   - const meshNormal = new Vector3(0, 0, 1)
55   - mesh.quaternion.setFromUnitVectors(meshNormal, coordVec3)
56   - return mesh
57   -}
58   -
59   -// 创建柱状
60   -export const createLightPillar = (options: {
61   - radius: number
62   - lon: number
63   - lat: number
64   - index: number
65   - textures: Record<string, Texture>
66   - punctuation: punctuation
67   -}) => {
68   - const height = options.radius * 0.3
69   - const geometry = new PlaneGeometry(options.radius * 0.05, height)
70   - geometry.rotateX(Math.PI / 2)
71   - geometry.translate(0, 0, height / 2)
72   - const material = new MeshBasicMaterial({
73   - map: options.textures.light_column,
74   - color: options.index == 0 ? options.punctuation.lightColumn.startColor : options.punctuation.lightColumn.endColor,
75   - transparent: true,
76   - side: DoubleSide,
77   - depthWrite: false //是否对深度缓冲区有任何的影响
78   - })
79   - const mesh = new Mesh(geometry, material)
80   - const group = new Group()
81   - // 两个光柱交叉叠加
82   - group.add(mesh, mesh.clone().rotateZ(Math.PI / 2)) //几何体绕x轴旋转了,所以mesh旋转轴变为z
83   - // 经纬度转球面坐标
84   - const SphereCoord = lon2xyz(options.radius, options.lon, options.lat) //SphereCoord球面坐标
85   - group.position.set(SphereCoord.x, SphereCoord.y, SphereCoord.z) //设置mesh位置
86   - const coordVec3 = new Vector3(SphereCoord.x, SphereCoord.y, SphereCoord.z).normalize()
87   - const meshNormal = new Vector3(0, 0, 1)
88   - group.quaternion.setFromUnitVectors(meshNormal, coordVec3)
89   - return group
90   -}
91   -
92   -// 光柱底座矩形平面
93   -export const createPointMesh = (options: { radius: number; lon: number; lat: number; material: MeshBasicMaterial }) => {
94   - const geometry = new PlaneGeometry(1, 1) //默认在XOY平面上
95   - const mesh = new Mesh(geometry, options.material)
96   - // 经纬度转球面坐标
97   - const coord = lon2xyz(options.radius * 1.001, options.lon, options.lat)
98   - const size = options.radius * 0.05 // 矩形平面Mesh的尺寸
99   - mesh.scale.set(size, size, size) // 设置mesh大小
100   -
101   - // 设置mesh位置
102   - mesh.position.set(coord.x, coord.y, coord.z)
103   - const coordVec3 = new Vector3(coord.x, coord.y, coord.z).normalize()
104   - const meshNormal = new Vector3(0, 0, 1)
105   - mesh.quaternion.setFromUnitVectors(meshNormal, coordVec3)
106   - return mesh
107   -}
108   -
109   -// 获取点
110   -export const getCirclePoints = (option: any) => {
111   - const list = []
112   - for (let j = 0; j < 2 * Math.PI - 0.1; j += (2 * Math.PI) / (option.number || 100)) {
113   - list.push([
114   - parseFloat((Math.cos(j) * (option.radius || 10)).toFixed(2)),
115   - 0,
116   - parseFloat((Math.sin(j) * (option.radius || 10)).toFixed(2))
117   - ])
118   - }
119   - if (option.closed) list.push(list[0])
120   - return list
121   -}
122   -
123   -// 创建线
124   -
125   -/**
126   - * 创建动态的线
127   - */
128   -export const createAnimateLine = (option: any) => {
129   - // 由多个点数组构成的曲线 通常用于道路
130   - const l: Array<any> = []
131   - option.pointList.forEach((e: Array<any>) => l.push(new Vector3(e[0], e[1], e[2])))
132   - const curve = new CatmullRomCurve3(l) // 曲线路径
133   -
134   - // 管道体
135   - const tubeGeometry = new TubeGeometry(curve, option.number || 50, option.radius || 1, option.radialSegments)
136   - return new Mesh(tubeGeometry, option.material)
137   -}
1   -
2   -export interface IEvents {
3   - resize: () => void
4   -}
1   -export interface IWord {
2   - dom: HTMLElement
3   - data: any
4   - width: number
5   - height: number
6   -}
\ No newline at end of file
1   -uniform vec3 glowColor;
2   -uniform float bias;
3   -uniform float power;
4   -uniform float time;
5   -varying vec3 vp;
6   -varying vec3 vNormal;
7   -varying vec3 vPositionNormal;
8   -uniform float scale;
9   -// 获取纹理
10   -uniform sampler2D map;
11   -// 纹理坐标
12   -varying vec2 vUv;
13   -
14   -void main(void){
15   - float a = pow( bias + scale * abs(dot(vNormal, vPositionNormal)), power );
16   - if(vp.y > time && vp.y < time + 20.0) {
17   - float t = smoothstep(0.0, 0.8, (1.0 - abs(0.5 - (vp.y - time) / 20.0)) / 3.0 );
18   - gl_FragColor = mix(gl_FragColor, vec4(glowColor, 1.0), t * t );
19   - }
20   - gl_FragColor = mix(gl_FragColor, vec4( glowColor, 1.0 ), a);
21   - float b = 0.8;
22   - gl_FragColor = gl_FragColor + texture2D( map, vUv );
23   -}
\ No newline at end of file
1   -
2   -varying vec2 vUv;
3   -varying vec3 vNormal;
4   -varying vec3 vp;
5   -varying vec3 vPositionNormal;
6   -void main(void){
7   - vUv = uv;
8   - vNormal = normalize( normalMatrix * normal ); // 转换到视图空间
9   - vp = position;
10   - vPositionNormal = normalize(( modelViewMatrix * vec4(position, 1.0) ).xyz);
11   - gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
12   -}
\ No newline at end of file
1   -/**
2   - * 资源文件
3   - * 把模型和图片分开进行加载
4   - */
5   -
6   -interface ITextures {
7   - name: string
8   - url: string
9   -}
10   -
11   -export interface IResources {
12   - textures?: ITextures[]
13   -}
14   -
15   -const fileSuffix = ['earth', 'gradient', 'redCircle', 'label', 'aperture', 'glow', 'light_column', 'aircraft']
16   -const textures: ITextures[] = []
17   -
18   -const modules = import.meta.globEager("../../images/earth/*");
19   -
20   -for(let item in modules) {
21   - const n = item.split('/').pop()
22   - if(n) {
23   - textures.push({
24   - name: n.split('.')[0],
25   - url: modules[item].default
26   - })
27   - }
28   -}
29   -
30   -const resources: IResources = {
31   - textures
32   -}
33   -
34   -export { resources }
1   -/**
2   - * 创建 threejs 四大天王
3   - * 场景、相机、渲染器、控制器
4   - */
5   -
6   -import * as THREE from 'three'
7   -import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
8   -
9   -export class Basic {
10   - public scene!: THREE.Scene
11   - public camera!: THREE.PerspectiveCamera
12   - public renderer!: THREE.WebGLRenderer
13   - public controls!: OrbitControls
14   - public dom: HTMLElement
15   -
16   - constructor(dom: HTMLElement) {
17   - this.dom = dom
18   - this.initScenes()
19   - this.setControls()
20   - }
21   -
22   - /**
23   - * 初始化场景
24   - */
25   - initScenes() {
26   - this.scene = new THREE.Scene()
27   -
28   - this.camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 100000)
29   - this.camera.position.set(0, 30, -250)
30   -
31   - this.renderer = new THREE.WebGLRenderer({
32   - // canvas: this.dom,
33   - alpha: true, // 透明
34   - antialias: true // 抗锯齿
35   - })
36   - this.renderer.setPixelRatio(window.devicePixelRatio) // 设置屏幕像素比
37   - this.renderer.setSize(window.innerWidth, window.innerHeight) // 设置渲染器宽高
38   - this.dom.appendChild(this.renderer.domElement) // 添加到dom中
39   - }
40   -
41   - /**
42   - * 设置控制器
43   - */
44   - setControls() {
45   - // 鼠标控制 相机,渲染dom
46   - this.controls = new OrbitControls(this.camera, this.renderer.domElement)
47   -
48   - this.controls.autoRotateSpeed = 3
49   - // 使动画循环使用时阻尼或自转 意思是否有惯性
50   - this.controls.enableDamping = true
51   - // 动态阻尼系数 就是鼠标拖拽旋转灵敏度
52   - this.controls.dampingFactor = 0.05
53   - // 是否可以缩放
54   - this.controls.enableZoom = true
55   - // 设置相机距离原点的最远距离
56   - this.controls.minDistance = 100
57   - // 设置相机距离原点的最远距离
58   - this.controls.maxDistance = 300
59   - // 是否开启右键拖拽
60   - this.controls.enablePan = false
61   - }
62   -}
1   -import {
2   - BufferAttribute,
3   - BufferGeometry,
4   - Color,
5   - DoubleSide,
6   - Group,
7   - Material,
8   - Mesh,
9   - MeshBasicMaterial,
10   - NormalBlending,
11   - Object3D,
12   - Points,
13   - PointsMaterial,
14   - ShaderMaterial,
15   - SphereGeometry,
16   - Sprite,
17   - SpriteMaterial,
18   - Texture,
19   - TextureLoader,
20   - Vector3
21   -} from 'three'
22   -
23   -import {
24   - createAnimateLine,
25   - createLightPillar,
26   - createPointMesh,
27   - createWaveMesh,
28   - getCirclePoints,
29   - lon2xyz
30   -} from '../Utils/common'
31   -import gsap from 'gsap'
32   -import { flyArc } from '../Utils/arc'
33   -import earthVertex from '../shaders/earth/vertex.vs?raw'
34   -import earthFragment from '../shaders/earth/fragment.fs?raw'
35   -
36   -export type punctuation = {
37   - circleColor: number
38   - lightColumn: {
39   - startColor: number // 起点颜色
40   - endColor: number // 终点颜色
41   - }
42   -}
43   -
44   -type options = {
45   - data: {
46   - startArray: {
47   - name: string
48   - E: number // 经度
49   - N: number // 维度
50   - }
51   - endArray: {
52   - name: string
53   - E: number // 经度
54   - N: number // 维度
55   - }[]
56   - }[]
57   - dom: HTMLElement
58   - textures: Record<string, Texture> // 贴图
59   - earth: {
60   - radius: number // 地球半径
61   - rotateSpeed: number // 地球旋转速度
62   - isRotation: boolean // 地球组是否自转
63   - }
64   - satellite: {
65   - show: boolean // 是否显示卫星
66   - rotateSpeed: number // 旋转速度
67   - size: number // 卫星大小
68   - number: number // 一个圆环几个球
69   - }
70   - punctuation: punctuation
71   - flyLine: {
72   - color: number // 飞线的颜色
73   - speed: number // 飞机拖尾线速度
74   - flyLineColor: number // 飞行线的颜色
75   - }
76   -}
77   -type uniforms = {
78   - glowColor: { value: Color }
79   - scale: { type: string; value: number }
80   - bias: { type: string; value: number }
81   - power: { type: string; value: number }
82   - time: { type: string; value: any }
83   - isHover: { value: boolean }
84   - map: { value?: Texture }
85   -}
86   -
87   -export default class earth {
88   - public group: Group
89   - public earthGroup: Group
90   -
91   - public around!: BufferGeometry
92   - public aroundPoints!: Points<BufferGeometry, PointsMaterial>
93   -
94   - public options: options
95   - public uniforms: uniforms
96   - public timeValue: number
97   -
98   - public earth!: Mesh<SphereGeometry, ShaderMaterial>
99   - public punctuationMaterial!: MeshBasicMaterial
100   - public markupPoint: Group
101   - public waveMeshArr: Object3D[]
102   -
103   - public circleLineList: any[]
104   - public circleList: any[]
105   - public x: number
106   - public n: number
107   - public isRotation: boolean
108   - public flyLineArcGroup!: Group
109   -
110   - constructor(options: options) {
111   - this.options = options
112   -
113   - this.group = new Group()
114   - this.group.name = 'group'
115   - this.group.scale.set(0, 0, 0)
116   - this.earthGroup = new Group()
117   - this.group.add(this.earthGroup)
118   - this.earthGroup.name = 'EarthGroup'
119   -
120   - // 标注点效果
121   - this.markupPoint = new Group()
122   - this.markupPoint.name = 'markupPoint'
123   - this.waveMeshArr = []
124   -
125   - // 卫星和标签
126   - this.circleLineList = []
127   - this.circleList = []
128   - this.x = 0
129   - this.n = 0
130   -
131   - // 地球自转
132   - this.isRotation = this.options.earth.isRotation
133   -
134   - // 扫光动画 shader
135   - this.timeValue = 200
136   -
137   - this.uniforms = {
138   - glowColor: {
139   - value: new Color(0x0cd1eb)
140   - },
141   - scale: {
142   - type: 'f',
143   - value: -1.0
144   - },
145   - bias: {
146   - type: 'f',
147   - value: 1.0
148   - },
149   - power: {
150   - type: 'f',
151   - value: 3.3
152   - },
153   - time: {
154   - type: 'f',
155   - value: this.timeValue
156   - },
157   - isHover: {
158   - value: false
159   - },
160   - map: {
161   - value: undefined
162   - }
163   - }
164   - }
165   -
166   - async init(): Promise<void> {
167   - return new Promise(resolve => {
168   - const init = async () => {
169   - this.createEarth() // 创建地球
170   - this.createEarthGlow() // 创建地球辉光
171   - this.createEarthAperture() // 创建地球的大气层
172   - await this.createMarkupPoint() // 创建柱状点位
173   - this.createAnimateCircle() // 创建环绕卫星
174   - this.createFlyLine() // 创建飞线
175   - this.show()
176   - resolve()
177   - }
178   - init()
179   - })
180   - }
181   -
182   - createEarth() {
183   - const earth_geometry = new SphereGeometry(this.options.earth.radius, 50, 50)
184   - const earth_border = new SphereGeometry(this.options.earth.radius + 10, 60, 60)
185   -
186   - const pointMaterial = new PointsMaterial({
187   - color: 0x81ffff, //设置颜色,默认 0xFFFFFF
188   - transparent: true,
189   - sizeAttenuation: true,
190   - opacity: 0.1,
191   - vertexColors: false, //定义材料是否使用顶点颜色,默认false ---如果该选项设置为true,则color属性失效
192   - size: 0.2 //定义粒子的大小。默认为1.0
193   - })
194   - const points = new Points(earth_border, pointMaterial) //将模型添加到场景
195   -
196   - this.earthGroup.add(points)
197   -
198   - this.uniforms.map.value = this.options.textures.earth
199   -
200   - const earth_material = new ShaderMaterial({
201   - // wireframe:true, // 显示模型线条
202   - uniforms: this.uniforms as any,
203   - vertexShader: earthVertex,
204   - fragmentShader: earthFragment
205   - })
206   -
207   - earth_material.needsUpdate = true
208   - this.earth = new Mesh(earth_geometry, earth_material)
209   - this.earth.name = 'earth'
210   - this.earthGroup.add(this.earth)
211   - }
212   -
213   - createEarthGlow() {
214   - const R = this.options.earth.radius //地球半径
215   -
216   - // TextureLoader创建一个纹理加载器对象,可以加载图片作为纹理贴图
217   - const texture = this.options.textures.glow // 加载纹理贴图
218   -
219   - // 创建精灵材质对象SpriteMaterial
220   - const spriteMaterial = new SpriteMaterial({
221   - map: texture, // 设置精灵纹理贴图
222   - color: 0x4390d1,
223   - transparent: true, //开启透明
224   - opacity: 0.7, // 可以通过透明度整体调节光圈
225   - depthWrite: false //禁止写入深度缓冲区数据
226   - })
227   -
228   - // 创建表示地球光圈的精灵模型
229   - const sprite = new Sprite(spriteMaterial)
230   - sprite.scale.set(R * 3.0, R * 3.0, 1) //适当缩放精灵
231   - this.earthGroup.add(sprite)
232   - }
233   -
234   - createEarthAperture() {
235   - const vertexShader = [
236   - 'varying vec3 vVertexWorldPosition;',
237   - 'varying vec3 vVertexNormal;',
238   - 'varying vec4 vFragColor;',
239   - 'void main(){',
240   - ' vVertexNormal = normalize(normalMatrix * normal);', //将法线转换到视图坐标系中
241   - ' vVertexWorldPosition = (modelMatrix * vec4(position, 1.0)).xyz;', //将顶点转换到世界坐标系中
242   - ' // set gl_Position',
243   - ' gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);',
244   - '}'
245   - ].join('\n')
246   -
247   - //大气层效果
248   - const AeroSphere = {
249   - uniforms: {
250   - coeficient: {
251   - type: 'f',
252   - value: 1.0
253   - },
254   - power: {
255   - type: 'f',
256   - value: 3
257   - },
258   - glowColor: {
259   - type: 'c',
260   - value: new Color(0x4390d1)
261   - }
262   - },
263   - vertexShader: vertexShader,
264   - fragmentShader: [
265   - 'uniform vec3 glowColor;',
266   - 'uniform float coeficient;',
267   - 'uniform float power;',
268   -
269   - 'varying vec3 vVertexNormal;',
270   - 'varying vec3 vVertexWorldPosition;',
271   -
272   - 'varying vec4 vFragColor;',
273   -
274   - 'void main(){',
275   - ' vec3 worldCameraToVertex = vVertexWorldPosition - cameraPosition;', //世界坐标系中从相机位置到顶点位置的距离
276   - ' vec3 viewCameraToVertex = (viewMatrix * vec4(worldCameraToVertex, 0.0)).xyz;', //视图坐标系中从相机位置到顶点位置的距离
277   - ' viewCameraToVertex= normalize(viewCameraToVertex);', //规一化
278   - ' float intensity = pow(coeficient + dot(vVertexNormal, viewCameraToVertex), power);',
279   - ' gl_FragColor = vec4(glowColor, intensity);',
280   - '}'
281   - ].join('\n')
282   - }
283   - //球体 辉光 大气层
284   - const material1 = new ShaderMaterial({
285   - uniforms: AeroSphere.uniforms,
286   - vertexShader: AeroSphere.vertexShader,
287   - fragmentShader: AeroSphere.fragmentShader,
288   - blending: NormalBlending,
289   - transparent: true,
290   - depthWrite: false
291   - })
292   - const sphere = new SphereGeometry(this.options.earth.radius + 0, 50, 50)
293   - const mesh = new Mesh(sphere, material1)
294   - this.earthGroup.add(mesh)
295   - }
296   -
297   - async createMarkupPoint() {
298   - await Promise.all(
299   - this.options.data.map(async item => {
300   - const radius = this.options.earth.radius
301   - const lon = item.startArray.E //经度
302   - const lat = item.startArray.N //纬度
303   -
304   - this.punctuationMaterial = new MeshBasicMaterial({
305   - color: this.options.punctuation.circleColor,
306   - map: this.options.textures.label,
307   - transparent: true, //使用背景透明的png贴图,注意开启透明计算
308   - depthWrite: false //禁止写入深度缓冲区数据
309   - })
310   -
311   - const mesh = createPointMesh({ radius, lon, lat, material: this.punctuationMaterial }) //光柱底座矩形平面
312   - this.markupPoint.add(mesh)
313   - const LightPillar = createLightPillar({
314   - radius: this.options.earth.radius,
315   - lon,
316   - lat,
317   - index: 0,
318   - textures: this.options.textures,
319   - punctuation: this.options.punctuation
320   - }) //光柱
321   - this.markupPoint.add(LightPillar)
322   - const WaveMesh = createWaveMesh({ radius, lon, lat, textures: this.options.textures }) //波动光圈
323   - this.markupPoint.add(WaveMesh)
324   - this.waveMeshArr.push(WaveMesh)
325   -
326   - await Promise.all(
327   - item.endArray.map(obj => {
328   - const lon = obj.E //经度
329   - const lat = obj.N //纬度
330   - const mesh = createPointMesh({ radius, lon, lat, material: this.punctuationMaterial }) //光柱底座矩形平面
331   - this.markupPoint.add(mesh)
332   - const LightPillar = createLightPillar({
333   - radius: this.options.earth.radius,
334   - lon,
335   - lat,
336   - index: 1,
337   - textures: this.options.textures,
338   - punctuation: this.options.punctuation
339   - }) //光柱
340   - this.markupPoint.add(LightPillar)
341   - const WaveMesh = createWaveMesh({ radius, lon, lat, textures: this.options.textures }) //波动光圈
342   - this.markupPoint.add(WaveMesh)
343   - this.waveMeshArr.push(WaveMesh)
344   - })
345   - )
346   - this.earthGroup.add(this.markupPoint)
347   - })
348   - )
349   - }
350   -
351   - createAnimateCircle() {
352   - // 创建 圆环 点
353   - const list = getCirclePoints({
354   - radius: this.options.earth.radius + 15,
355   - number: 150, //切割数
356   - closed: true // 闭合
357   - })
358   - const mat = new MeshBasicMaterial({
359   - color: '#0c3172',
360   - transparent: true,
361   - opacity: 0.4,
362   - side: DoubleSide
363   - })
364   - const line = createAnimateLine({
365   - pointList: list,
366   - material: mat,
367   - number: 100,
368   - radius: 0.1
369   - })
370   - this.earthGroup.add(line)
371   -
372   - // 在clone两条线出来
373   - const l2 = line.clone()
374   - l2.scale.set(1.2, 1.2, 1.2)
375   - l2.rotateZ(Math.PI / 6)
376   - this.earthGroup.add(l2)
377   -
378   - const l3 = line.clone()
379   - l3.scale.set(0.8, 0.8, 0.8)
380   - l3.rotateZ(-Math.PI / 6)
381   - this.earthGroup.add(l3)
382   -
383   - /**
384   - * 旋转的球
385   - */
386   - const ball = new Mesh(
387   - new SphereGeometry(this.options.satellite.size, 32, 32),
388   - new MeshBasicMaterial({
389   - color: '#e0b187' // 745F4D
390   - })
391   - )
392   -
393   - const ball2 = new Mesh(
394   - new SphereGeometry(this.options.satellite.size, 32, 32),
395   - new MeshBasicMaterial({
396   - color: '#628fbb' // 324A62
397   - })
398   - )
399   -
400   - const ball3 = new Mesh(
401   - new SphereGeometry(this.options.satellite.size, 32, 32),
402   - new MeshBasicMaterial({
403   - color: '#806bdf' //6D5AC4
404   - })
405   - )
406   -
407   - this.circleLineList.push(line, l2, l3)
408   - ball.name = ball2.name = ball3.name = '卫星'
409   -
410   - for (let i = 0; i < this.options.satellite.number; i++) {
411   - const ball01 = ball.clone()
412   - // 一根线上总共有几个球,根据数量平均分布一下
413   - const num = Math.floor(list.length / this.options.satellite.number)
414   - ball01.position.set(list[num * (i + 1)][0] * 1, list[num * (i + 1)][1] * 1, list[num * (i + 1)][2] * 1)
415   - line.add(ball01)
416   -
417   - const ball02 = ball2.clone()
418   - const num02 = Math.floor(list.length / this.options.satellite.number)
419   - ball02.position.set(list[num02 * (i + 1)][0] * 1, list[num02 * (i + 1)][1] * 1, list[num02 * (i + 1)][2] * 1)
420   - l2.add(ball02)
421   -
422   - const ball03 = ball2.clone()
423   - const num03 = Math.floor(list.length / this.options.satellite.number)
424   - ball03.position.set(list[num03 * (i + 1)][0] * 1, list[num03 * (i + 1)][1] * 1, list[num03 * (i + 1)][2] * 1)
425   - l3.add(ball03)
426   - }
427   - }
428   -
429   - createFlyLine() {
430   - this.flyLineArcGroup = new Group()
431   - this.flyLineArcGroup.userData['flyLineArray'] = []
432   - this.earthGroup.add(this.flyLineArcGroup)
433   - this.options.data.forEach(cities => {
434   - cities.endArray.forEach(item => {
435   - // 调用函数flyArc绘制球面上任意两点之间飞线圆弧轨迹
436   - const arcline = flyArc(
437   - this.options.earth.radius,
438   - cities.startArray.E,
439   - cities.startArray.N,
440   - item.E,
441   - item.N,
442   - this.options.flyLine
443   - )
444   -
445   - this.flyLineArcGroup.add(arcline) // 飞线插入flyArcGroup中
446   - this.flyLineArcGroup.userData['flyLineArray'].push(arcline.userData['flyLine'])
447   - })
448   - })
449   - }
450   -
451   - show() {
452   - gsap.to(this.group.scale, {
453   - x: 1,
454   - y: 1,
455   - z: 1,
456   - duration: 2,
457   - ease: 'Quadratic'
458   - })
459   - }
460   -
461   - render() {
462   - this.flyLineArcGroup?.userData['flyLineArray']?.forEach((fly: any) => {
463   - fly.rotation.z += this.options.flyLine.speed // 调节飞线速度
464   - if (fly.rotation.z >= fly.flyEndAngle) fly.rotation.z = 0
465   - })
466   -
467   - if (this.isRotation) {
468   - this.earthGroup.rotation.y += this.options.earth.rotateSpeed
469   - }
470   -
471   - this.circleLineList.forEach(e => {
472   - e.rotateY(this.options.satellite.rotateSpeed)
473   - })
474   -
475   - this.uniforms.time.value =
476   - this.uniforms.time.value < -this.timeValue ? this.timeValue : this.uniforms.time.value - 1
477   -
478   - if (this.waveMeshArr.length) {
479   - this.waveMeshArr.forEach((mesh: any) => {
480   - mesh.userData['scale'] += 0.007
481   - mesh.scale.set(
482   - mesh.userData['size'] * mesh.userData['scale'],
483   - mesh.userData['size'] * mesh.userData['scale'],
484   - mesh.userData['size'] * mesh.userData['scale']
485   - )
486   - if (mesh.userData['scale'] <= 1.5) {
487   - (mesh.material as Material).opacity = (mesh.userData['scale'] - 1) * 2 //2等于1/(1.5-1.0),保证透明度在0~1之间变化
488   - } else if (mesh.userData['scale'] > 1.5 && mesh.userData['scale'] <= 2) {
489   - (mesh.material as Material).opacity = 1 - (mesh.userData['scale'] - 1.5) * 2 //2等于1/(2.0-1.5) mesh缩放2倍对应0 缩放1.5被对应1
490   - } else {
491   - mesh.userData['scale'] = 1
492   - }
493   - })
494   - }
495   - }
496   -}
1   -/**
2   - * 资源管理和加载
3   - */
4   -import { LoadingManager, Texture, TextureLoader } from 'three'
5   -import { loadingStart, loadingFinish, loadingError } from '@/utils'
6   -import { resources } from './Assets'
7   -export class Resources {
8   - private manager!: LoadingManager
9   - private callback: () => void
10   - private textureLoader!: InstanceType<typeof TextureLoader>
11   - public textures: Record<string, Texture>
12   - constructor(callback: () => void) {
13   - this.callback = callback // 资源加载完成的回调
14   - this.textures = {} // 贴图对象
15   - this.setLoadingManager()
16   - this.loadResources()
17   - }
18   -
19   - /**
20   - * 管理加载状态
21   - */
22   - private setLoadingManager() {
23   - this.manager = new LoadingManager()
24   - // 开始加载
25   - this.manager.onStart = () => {
26   - loadingStart()
27   - }
28   - // 加载完成
29   - this.manager.onLoad = () => {
30   - this.callback()
31   - }
32   - // 正在进行中
33   - this.manager.onProgress = url => {
34   - loadingFinish()
35   - }
36   -
37   - this.manager.onError = url => {
38   - loadingError()
39   - window['$message'].error('数据加载失败,请刷新重试!')
40   - }
41   - }
42   -
43   - /**
44   - * 加载资源
45   - */
46   - private loadResources(): void {
47   - this.textureLoader = new TextureLoader(this.manager)
48   - resources.textures?.forEach(item => {
49   - this.textureLoader.load(item.url, t => {
50   - this.textures[item.name] = t
51   - })
52   - })
53   - }
54   -}
1   -import { MeshBasicMaterial, PerspectiveCamera, Scene, ShaderMaterial, WebGLRenderer } from 'three'
2   -import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
3   -// interfaces
4   -import { IWord } from '../interfaces/IWord'
5   -import { Basic } from './Basic'
6   -import { Resources } from './Resources'
7   -// earth
8   -import Earth from './Earth'
9   -
10   -export default class World {
11   - public basic: Basic
12   - public scene: Scene
13   - public camera: PerspectiveCamera
14   - public renderer: WebGLRenderer
15   - public controls: OrbitControls
16   - public material!: ShaderMaterial | MeshBasicMaterial
17   - public resources: Resources
18   - public option: IWord
19   - public earth!: Earth
20   -
21   - constructor(option: IWord) {
22   - /**
23   - * 加载资源
24   - */
25   - this.option = option
26   - this.basic = new Basic(option.dom)
27   - this.scene = this.basic.scene
28   - this.renderer = this.basic.renderer
29   - this.controls = this.basic.controls
30   - this.camera = this.basic.camera
31   - this.updateSize()
32   - this.resources = new Resources(async () => {
33   - await this.createEarth()
34   - // 开始渲染
35   - this.render()
36   - })
37   - }
38   -
39   - async createEarth(data?: any) {
40   - // 资源加载完成,开始制作地球,注释在new Earth()类型里面
41   - this.earth = new Earth({
42   - data: data || this.option.data,
43   - dom: this.option.dom,
44   - textures: this.resources.textures,
45   - earth: {
46   - radius: 50,
47   - rotateSpeed: 0.002,
48   - isRotation: true
49   - },
50   - satellite: {
51   - show: true,
52   - rotateSpeed: -0.01,
53   - size: 1,
54   - number: 2
55   - },
56   - punctuation: {
57   - circleColor: 0x3892ff,
58   - lightColumn: {
59   - startColor: 0xe4007f, // 起点颜色
60   - endColor: 0xffffff // 终点颜色
61   - }
62   - },
63   - flyLine: {
64   - color: 0xf3ae76, // 飞线的颜色
65   - flyLineColor: 0xff7714, // 飞行线的颜色
66   - speed: 0.004 // 拖尾飞线的速度
67   - }
68   - })
69   -
70   - this.scene.add(this.earth.group)
71   - await this.earth.init()
72   - }
73   -
74   - /**
75   - * 渲染函数
76   - */
77   - public render() {
78   - requestAnimationFrame(this.render.bind(this))
79   - this.renderer.render(this.scene, this.camera)
80   - this.controls && this.controls.update()
81   - this.earth && this.earth.render()
82   - }
83   -
84   - // 更新
85   - public updateSize(width?: number, height?: number) {
86   - let w = width || this.option.width
87   - let h = height || this.option.height
88   - // 取小值
89   - if (w < h) h = w
90   - else w = h
91   -
92   - this.renderer.setSize(w, h)
93   - this.camera.aspect = w / h
94   - this.camera.updateProjectionMatrix()
95   - }
96   -
97   - // 数据更新重新渲染
98   - public updateData(data?: any) {
99   - if (!this.earth.group) return
100   - // 先删除旧的
101   - this.scene.remove(this.earth.group)
102   - // 递归遍历组对象group释放所有后代网格模型绑定几何体占用内存
103   - this.earth.group.traverse((obj: any) => {
104   - if (obj.type === 'Mesh') {
105   - obj.geometry.dispose()
106   - obj.material.dispose()
107   - }
108   - })
109   - // 重新创建
110   - this.createEarth(data)
111   - }
112   -}
1   -import { PublicConfigClass } from '@/packages/public'
2   -import { CreateComponentType } from '@/packages/index.d'
3   -import { chartInitConfig } from '@/settings/designSetting'
4   -import { ThreeEarth01Config } from './index'
5   -import dataJson from './data.json'
6   -import cloneDeep from 'lodash/cloneDeep'
7   -
8   -export const option = {
9   - dataset: dataJson
10   -}
11   -
12   -export default class Config extends PublicConfigClass implements CreateComponentType {
13   - public key = ThreeEarth01Config.key
14   - public attr = { ...chartInitConfig, w: 800, h: 800, zIndex: -1 }
15   - public chartConfig = cloneDeep(ThreeEarth01Config)
16   - public option = cloneDeep(option)
17   -}
1   -<template></template>
2   -
3   -<script setup lang="ts">
4   -import { PropType } from 'vue'
5   -import { CollapseItem, SettingItemBox, SettingItem } from '@/components/Pages/ChartItemSetting'
6   -import { option } from './config.vue'
7   -
8   -const props = defineProps({
9   - optionData: {
10   - type: Object as PropType<typeof option>,
11   - required: true
12   - }
13   -})
14   -</script>
1   -[
2   - {
3   - "startArray": {
4   - "name": "杭州",
5   - "N": 30.246026,
6   - "E": 120.210792
7   - },
8   - "endArray": [
9   - {
10   - "name": "曼谷",
11   - "N": 22,
12   - "E": 100.49074172973633
13   - },
14   - {
15   - "name": "澳大利亚",
16   - "N": -23.68477416688374,
17   - "E": 133.857421875
18   - },
19   -
20   - {
21   - "name": "新疆维吾尔自治区",
22   - "N": 41.748,
23   - "E": 84.9023
24   - },
25   -
26   - {
27   - "name": "德黑兰",
28   - "N": 35,
29   - "E": 51
30   - },
31   - {
32   - "name": "德黑兰",
33   - "N": 35,
34   - "E": 51
35   - },
36   - {
37   - "name": "美国",
38   - "N": 34.125447565116126,
39   - "E": 241.7431640625
40   - },
41   - {
42   - "name": "英国",
43   - "N": 51.508742458803326,
44   - "E": 359.82421875
45   - },
46   - {
47   - "name": "巴西",
48   - "N": -9.96885060854611,
49   - "E": 668.1445312499999
50   - }
51   - ]
52   - },
53   - {
54   - "startArray": {
55   - "name": "北京",
56   - "N": 39.89491,
57   - "E": 116.322056
58   - },
59   - "endArray": [
60   - {
61   - "name": "西藏",
62   - "N": 29.660361,
63   - "E": 91.132212
64   - },
65   - {
66   - "name": "广西",
67   - "N": 22.830824,
68   - "E": 108.30616
69   - },
70   -
71   - {
72   - "name": "江西",
73   - "N": 28.676493,
74   - "E": 115.892151
75   - },
76   -
77   - {
78   - "name": "贵阳",
79   - "N": 26.647661,
80   - "E": 106.630153
81   - }
82   - ]
83   - }
84   -]
1   -import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
2   -import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
3   -
4   -export const ThreeEarth01Config: ConfigType = {
5   - key: 'ThreeEarth01',
6   - chartKey: 'VThreeEarth01',
7   - conKey: 'VCThreeEarth01',
8   - title: '三维地球',
9   - category: ChatCategoryEnum.THREEDANIMATION,
10   - categoryName: ChatCategoryEnumName.THREEDANIMATION,
11   - package: PackagesCategoryEnum.ARTOONS,
12   - chartFrame: ChartFrameEnum.STATIC,
13   - image: 'threeEarth01.png'
14   -}
1   -<template>
2   - <div ref="chartRef"></div>
3   -</template>
4   -
5   -<script setup lang="ts">
6   -import { onMounted, PropType, ref, toRefs, watch } from 'vue'
7   -import { CreateComponentType } from '@/packages'
8   -import { useChartDataFetch } from '@/hooks'
9   -import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
10   -import { option } from './config.vue'
11   -import World from './code/world/Word'
12   -import throttle from 'lodash/throttle'
13   -
14   -const props = defineProps({
15   - chartConfig: {
16   - type: Object as PropType<CreateComponentType & typeof option>,
17   - required: true
18   - }
19   -})
20   -
21   -const chartEditStore = useChartEditStore()
22   -
23   -const chartRef = ref<HTMLElement>()
24   -const { w, h } = toRefs(props.chartConfig.attr)
25   -let threeClassInstance: World
26   -
27   -// 初始化
28   -const init = () => {
29   - const dom: HTMLElement | undefined = chartRef.value
30   - if (dom) {
31   - threeClassInstance = new World({
32   - dom: dom,
33   - data: props.chartConfig.option.dataset,
34   - width: w.value,
35   - height: h.value
36   - })
37   - }
38   -}
39   -
40   -const updateData = (data: any) => {
41   - try {
42   - threeClassInstance.updateData(data)
43   - } catch (error) {
44   - console.log(error)
45   - }
46   -}
47   -
48   -// 改变大小
49   -watch(
50   - () => [w.value, h.value],
51   - throttle(([newWidth], [newHeight]) => {
52   - threeClassInstance.updateSize(newWidth, newHeight)
53   - }, 100)
54   -)
55   -
56   -watch(
57   - () => props.chartConfig.option.dataset,
58   - (newData: any) => {
59   - updateData(newData)
60   - },
61   - {
62   - deep: false
63   - }
64   -)
65   -
66   -// DOM 渲染之后进行初始化
67   -onMounted(() => {
68   - try {
69   - if (navigator.userAgent.indexOf('Chrome') < -1 || navigator.userAgent.indexOf('Edg') < -1) {
70   - window['$message'].error('三维地图组件仅在【谷歌】浏览器上能正常展示!')
71   - chartEditStore.removeComponentList(undefined, false)
72   - return
73   - }
74   - init()
75   - } catch (error) {
76   - console.log(error)
77   - }
78   -})
79   -
80   -useChartDataFetch(props.chartConfig, useChartEditStore, updateData)
81   -</script>
1   -import {ThreeEarth01Config} from './ThreeEarth01/index'
2   -
3   -
4   -export default [ThreeEarth01Config]
1   -import { echartOptionProfixHandle, PublicConfigClass } from '@/packages/public'
2   -import { CreateComponentType } from '@/packages/index.d'
3   -import { WaterPoloConfig } from './index'
4   -import cloneDeep from 'lodash/cloneDeep'
5   -
6   -export const shapes = [
7   - {
8   - label: '圆形',
9   - value: 'circle'
10   - },
11   - {
12   - label: '正方形',
13   - value: 'rect'
14   - },
15   - {
16   - label: '带圆角的正方形',
17   - value: 'roundRect'
18   - },
19   - {
20   - label: '正三角形',
21   - value: 'triangle'
22   - },
23   - {
24   - label: '菱形',
25   - value: 'diamond'
26   - },
27   - {
28   - label: '水滴',
29   - value: 'pin'
30   - },
31   - {
32   - label: '箭头',
33   - value: 'arrow'
34   - },
35   -]
36   -
37   -export const includes = []
38   -
39   -export const option = {
40   - dataset: 0.5,
41   - series: [
42   - {
43   - type: 'liquidFill',
44   - shape: shapes[0].value,
45   - radius: '90%',
46   - data: [0],
47   - center: ['50%', '50%'],
48   - color: [
49   - {
50   - type: 'linear',
51   - x: 0,
52   - y: 0,
53   - x2: 0,
54   - y2: 1,
55   - colorStops: [
56   - {
57   - offset: 0,
58   - color: '#446bf5',
59   - },
60   - {
61   - offset: 1,
62   - color: '#2ca3e2',
63   - },
64   - ],
65   - globalCoord: false,
66   - },
67   - ],
68   - backgroundStyle: {
69   - borderWidth: 1,
70   - color: 'rgba(51, 66, 127, 0.7)',
71   - },
72   - label: {
73   - normal: {
74   - textStyle: {
75   - fontSize: 50,
76   - color: '#fff',
77   - },
78   - },
79   - },
80   - outline: {
81   - show: false,
82   - borderDistance: 10,
83   - itemStyle: {
84   - borderWidth: 2,
85   - borderColor: '#112165'
86   - }
87   - }
88   - }
89   - ]
90   -}
91   -
92   -export default class Config extends PublicConfigClass implements CreateComponentType
93   -{
94   - public key = WaterPoloConfig.key
95   - public chartConfig = cloneDeep(WaterPoloConfig)
96   - public option = echartOptionProfixHandle(option, includes)
97   -}
1   -<template>
2   - <CollapseItem
3   - v-for="(item, index) in seriesList"
4   - :key="index"
5   - name="水球"
6   - :expanded="true"
7   - >
8   - <SettingItemBox name="内容">
9   - <SettingItem name="数值">
10   - <n-input-number
11   - v-model:value="item.data[0]"
12   - :min="0"
13   - :step="0.01"
14   - size="small"
15   - placeholder="水球数值"
16   - ></n-input-number>
17   - </SettingItem>
18   - <SettingItem name="形状">
19   - <n-select v-model:value="item.shape" :options="shapes" placeholder="选择形状" />
20   - </SettingItem>
21   - <SettingItem name="文本">
22   - <n-input-number v-model:value="item.label.normal.textStyle.fontSize" :min="0" :step="1" size="small" placeholder="文字大小">
23   - </n-input-number>
24   - </SettingItem>
25   - <SettingItem name="颜色1">
26   - <n-color-picker
27   - size="small"
28   - :modes="['hex']"
29   - v-model:value="item.color[0].colorStops[0].color"
30   - ></n-color-picker>
31   - </SettingItem>
32   - <SettingItem name="颜色2">
33   - <n-color-picker
34   - size="small"
35   - :modes="['hex']"
36   - v-model:value="item.color[0].colorStops[1].color"
37   - ></n-color-picker>
38   - </SettingItem>
39   - </SettingItemBox>
40   - <SettingItemBox name="背景" :alone="true">
41   - <SettingItem>
42   - <n-color-picker
43   - size="small"
44   - :modes="['hex']"
45   - v-model:value="item.backgroundStyle.color"
46   - ></n-color-picker>
47   - </SettingItem>
48   - </SettingItemBox>
49   - </CollapseItem>
50   -</template>
51   -
52   -<script setup lang="ts">
53   -import { PropType, computed } from 'vue'
54   -import { option, shapes } from './config'
55   -import {
56   - CollapseItem,
57   - SettingItemBox,
58   - SettingItem,
59   -} from '@/components/Pages/ChartItemSetting'
60   -
61   -const props = defineProps({
62   - optionData: {
63   - type: Object as PropType<typeof option>,
64   - required: true,
65   - },
66   -})
67   -
68   -const seriesList = computed(() => {
69   - return props.optionData.series
70   -})
71   -</script>
1   -import { ConfigType, PackagesCategoryEnum, ChartFrameEnum } from '@/packages/index.d'
2   -import { ChatCategoryEnum, ChatCategoryEnumName } from '../../index.d'
3   -
4   -export const WaterPoloConfig: ConfigType = {
5   - key: 'WaterPolo',
6   - chartKey: 'VWaterPolo',
7   - conKey: 'VCWaterPolo',
8   - title: '水球图',
9   - category: ChatCategoryEnum.TWODANIMATION,
10   - categoryName: ChatCategoryEnumName.TWODANIMATION,
11   - package: PackagesCategoryEnum.ARTOONS,
12   - chartFrame: ChartFrameEnum.COMMON,
13   - image: 'water_WaterPolo.png'
14   -}
1   -<template>
2   - <v-chart :theme="themeColor" :option="option.value" autoresize></v-chart>
3   -</template>
4   -
5   -<script setup lang="ts">
6   -import { PropType, watch, reactive } from 'vue'
7   -import VChart from 'vue-echarts'
8   -import { use } from 'echarts/core'
9   -import 'echarts-liquidfill/src/liquidFill.js'
10   -import { CanvasRenderer } from 'echarts/renderers'
11   -import { GridComponent } from 'echarts/components'
12   -import config from './config'
13   -import { isPreview, isString, isNumber } from '@/utils'
14   -import { chartColorsSearch, defaultTheme } from '@/settings/chartThemes/index'
15   -import { useChartEditStore } from '@/store/modules/chartEditStore/chartEditStore'
16   -import { useChartDataFetch } from '@/hooks'
17   -
18   -const props = defineProps({
19   - themeSetting: {
20   - type: Object,
21   - required: true
22   - },
23   - themeColor: {
24   - type: Object,
25   - required: true
26   - },
27   - chartConfig: {
28   - type: Object as PropType<config>,
29   - required: true
30   - }
31   -})
32   -
33   -use([CanvasRenderer, GridComponent])
34   -
35   -const chartEditStore = useChartEditStore()
36   -
37   -const option = reactive({
38   - value: {}
39   -})
40   -
41   -// 渐变色处理
42   -watch(
43   - () => chartEditStore.getEditCanvasConfig.chartThemeColor,
44   - (newColor: keyof typeof chartColorsSearch) => {
45   - try {
46   - if (!isPreview()) {
47   - const themeColor = chartColorsSearch[newColor] || chartColorsSearch[defaultTheme]
48   - // 背景颜色
49   - props.chartConfig.option.series[0].backgroundStyle.color = themeColor[2]
50   - // 水球颜色
51   - props.chartConfig.option.series[0].color[0].colorStops = [
52   - {
53   - offset: 0,
54   - color: themeColor[0]
55   - },
56   - {
57   - offset: 1,
58   - color: themeColor[1]
59   - }
60   - ]
61   - }
62   - option.value = props.chartConfig.option
63   - } catch (error) {
64   - console.log(error)
65   - }
66   - },
67   - {
68   - immediate: true
69   - }
70   -)
71   -
72   -// 数据处理
73   -const dataHandle = (newData: number | string) => {
74   - newData = isString(newData) ? parseFloat(newData) : newData
75   - return parseFloat(newData.toFixed(2))
76   -}
77   -
78   -// 编辑
79   -watch(
80   - () => props.chartConfig.option.dataset,
81   - newData => {
82   - if (!isString(newData) && !isNumber(newData)) return
83   - props.chartConfig.option.series[0].data = [dataHandle(newData)]
84   - option.value = props.chartConfig.option
85   - },
86   - {
87   - immediate: true,
88   - deep: false
89   - }
90   -)
91   -
92   -// 预览
93   -useChartDataFetch(props.chartConfig, useChartEditStore, (newData: number) => {
94   - // @ts-ignore
95   - option.value.series[0].data = [dataHandle(newData)]
96   -})
97   -</script>
1   -import {WaterPoloConfig} from './WaterPolo/index'
2   -
3   -
4   -export default [WaterPoloConfig]
1   -export enum ChatCategoryEnum {
2   - TWODANIMATION = 'TwoDAnimations',
3   -
4   - THREEDANIMATION = 'ThreeDAnimations',
5   - TITLE = 'Titles',
6   - MORE = 'Mores',
7   -
8   -}
9   -
10   -export enum ChatCategoryEnumName {
11   - TITLE = '标题',
12   - TWODANIMATION = '2D动画',
13   - THREEDANIMATION = '3D动画',
14   -
15   - MORE = '更多',
16   -}
1   -import Mores from './Mores'
2   -import TwoDAnimations from './TwoDAnimations'
3   -import ThreeDAnimations from './ThreeDAnimations'
4   -
5   -export const ArtoonsList = [...TwoDAnimations, ...ThreeDAnimations, ...Mores,]
  1 +import { PublicConfigClass } from '@/packages/public'
  2 +import { CreateComponentType } from '@/packages/index.d'
  3 +import { LeftCenterRightHeadConfig } from './index'
  4 +import cloneDeep from 'lodash/cloneDeep'
  5 +
  6 +export const option = {
  7 + dataset: '物联网平台数据统计',
  8 + bgSrc: 'src/assets/images/chart/headbackground/bg_top.png',
  9 + fontSize: 36,
  10 + showRight:true,
  11 + textColor:'#00f6ff',
  12 + textRightSizeColor:'#ffffff',
  13 + textRightFontSize:14,
  14 + x:0,
  15 + y:0,
  16 + xT:0,
  17 + yT:0,
  18 +}
  19 +
  20 +export default class Config extends PublicConfigClass implements CreateComponentType {
  21 + public key = LeftCenterRightHeadConfig.key
  22 + public chartConfig = cloneDeep(LeftCenterRightHeadConfig)
  23 + public option = cloneDeep(option)
  24 +}
... ...
  1 +<template>
  2 + <collapse-item name="信息" :expanded="true">
  3 + <setting-item-box name="背景选择" :alone="true">
  4 + <setting-item>
  5 + <n-select
  6 + size="small"
  7 + placeholder="请选择您要使用的背景"
  8 + style="width: 250px"
  9 + v-model:value="selectValue"
  10 + :options="selectBgOptions"
  11 + @update:value="selectBgValueHandle"
  12 + />
  13 + </setting-item>
  14 + </setting-item-box>
  15 + <setting-item-box name="文字" :alone="true">
  16 + <setting-item>
  17 + <n-input v-model:value="optionData.dataset" size="small"></n-input>
  18 + </setting-item>
  19 + </setting-item-box>
  20 + </collapse-item>
  21 + <collapse-item name="样式" :expanded="true">
  22 + <setting-item-box name="文字">
  23 + <setting-item name="字体大小">
  24 + <n-input-number v-model:value="optionData.fontSize" size="small" placeholder="字体大小"></n-input-number>
  25 + </setting-item>
  26 + </setting-item-box>
  27 + <setting-item-box name="文字颜色">
  28 + <setting-item name="颜色">
  29 + <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.textColor"></n-color-picker>
  30 + </setting-item>
  31 + </setting-item-box>
  32 + <setting-item-box name="位置x轴">
  33 + <setting-item name="字体位置x轴">
  34 + <n-input-number v-model:value="optionData.x" size="small" placeholder="字体位置"></n-input-number>
  35 + </setting-item>
  36 + </setting-item-box>
  37 + <setting-item-box name="位置y轴">
  38 + <setting-item name="字体位置y轴">
  39 + <n-input-number v-model:value="optionData.y" size="small" placeholder="字体位置"></n-input-number>
  40 + </setting-item>
  41 + </setting-item-box>
  42 + </collapse-item>
  43 + <collapse-item name="右侧" :expanded="true">
  44 + <setting-item-box name="是否显示">
  45 + <setting-item name="">
  46 + <n-switch @change="handleChange" v-model:value="optionData.showRight"/>
  47 + </setting-item>
  48 + </setting-item-box>
  49 + <setting-item-box name="文字">
  50 + <setting-item name="字体大小">
  51 + <n-input-number v-model:value="optionData.textRightFontSize" size="small"
  52 + placeholder="字体大小"></n-input-number>
  53 + </setting-item>
  54 + <setting-item name="字体位置x轴">
  55 + <n-input-number v-model:value="optionData.xT" size="small" placeholder="字体位置"></n-input-number>
  56 + </setting-item>
  57 + <setting-item name="字体位置y轴">
  58 + <n-input-number v-model:value="optionData.yT" size="small" placeholder="字体位置"></n-input-number>
  59 + </setting-item>
  60 + </setting-item-box>
  61 + <setting-item-box name="时间颜色">
  62 + <setting-item name="颜色">
  63 + <n-color-picker size="small" :modes="['hex']" v-model:value="optionData.textRightSizeColor"></n-color-picker>
  64 + </setting-item>
  65 + </setting-item-box>
  66 + </collapse-item>
  67 +</template>
  68 +
  69 +<script setup lang="ts">
  70 +import {PropType, ref} from 'vue'
  71 +import {option} from './config'
  72 +import {
  73 + CollapseItem,
  74 + SettingItemBox,
  75 + SettingItem
  76 +} from '@/components/Pages/ChartItemSetting'
  77 +import {SelectOption} from "naive-ui";
  78 +
  79 +const props = defineProps({
  80 + optionData: {
  81 + type: Object as PropType<typeof option>,
  82 + required: true
  83 + }
  84 +})
  85 +
  86 +const selectBgOptions = ref<Array<SelectOption>>([])
  87 +
  88 +const selectValue = ref('')
  89 +
  90 +//TODO待封装 成传文件夹名字获取下面所有图片
  91 +const getFetchImages = () => {
  92 + const imagesModules = import.meta.globEager('@/assets/images/chart/headbackground/*')
  93 + for (const key in imagesModules) {
  94 + selectBgOptions.value.push({
  95 + label: imagesModules[key]?.default.slice(25),
  96 + value: imagesModules[key]?.default
  97 + })
  98 + }
  99 +}
  100 +getFetchImages()
  101 +
  102 +const selectBgValueHandle = (value: string) => {
  103 + selectValue.value = value
  104 + props.optionData.bgSrc = value
  105 +}
  106 +
  107 +const handleChange = (value: boolean) => {
  108 + props.optionData.showRight = value
  109 +}
  110 +</script>
... ...
  1 +import {ConfigType, PackagesCategoryEnum, ChartFrameEnum} from '@/packages/index.d'
  2 +import {ChatCategoryEnum, ChatCategoryEnumName} from '../../index.d'
  3 +
  4 +export const LeftCenterRightHeadConfig: ConfigType = {
  5 + key: 'LeftCenterRightHead',
  6 + chartKey: 'VLeftCenterRightHead',
  7 + conKey: 'VCLeftCenterRightHead',
  8 + title: '通用头部',
  9 + category: ChatCategoryEnum.HEADCOMBINATION,
  10 + categoryName: ChatCategoryEnumName.HEADCOMBINATION,
  11 + package: PackagesCategoryEnum.COMPOSES,
  12 + chartFrame: ChartFrameEnum.COMMON,
  13 + image: 'left_center_rightHead.png',
  14 +}
... ...
  1 +<template>
  2 + <div class="go-text-box">
  3 + <n-grid :style="{'background-image': 'url('+option.configOption.bgSrc+')'}" class="go-n-grid" :x-gap="12" :y-gap="3"
  4 + :cols="3" layout-shift-disabled>
  5 + <n-grid-item>
  6 + <!-- 占位-->
  7 + <div></div>
  8 + </n-grid-item>
  9 + <n-grid-item>
  10 + <span
  11 + style="position:relative"
  12 + :style="{ top:option.configOption.y+'px',marginLeft:option.configOption.x+'px',color: option.configOption.textColor, fontSize: option.configOption.fontSize + 'px' }">{{
  13 + option.configOption.dataset
  14 + }}</span>
  15 + </n-grid-item>
  16 + <n-grid-item>
  17 + <span style="position:relative" v-if="option.configOption.showRight"
  18 + :style="{ top:option.configOption.yT+'px',marginLeft:option.configOption.xT+'px',color: option.configOption.textRightSizeColor, fontSize: option.configOption.textRightFontSize + 'px' }">{{
  19 + newData
  20 + }}</span>
  21 + </n-grid-item>
  22 + </n-grid>
  23 + </div>
  24 +</template>
  25 +<script setup lang="ts">
  26 +import {PropType, toRefs, shallowReactive, watch, onMounted, onUnmounted, ref} from 'vue'
  27 +import {CreateComponentType} from '@/packages/index.d'
  28 +import {useChartDataFetch} from '@/hooks'
  29 +import {useChartEditStore} from '@/store/modules/chartEditStore/chartEditStore'
  30 +import {option as configOption} from './config'
  31 +
  32 +const props = defineProps({
  33 + chartConfig: {
  34 + type: Object as PropType<CreateComponentType>,
  35 + required: true
  36 + }
  37 +})
  38 +
  39 +const option = shallowReactive({
  40 + configOption
  41 +})
  42 +
  43 +let yearMonthDay = ref('2021-2-3')
  44 +
  45 +let nowData = ref('08:00:00')
  46 +
  47 +let newData = ref('2021-2-3 08:00:00')
  48 +
  49 +let timer: any = null
  50 +
  51 +//默认设置宽高距离位置
  52 +props.chartConfig.attr.w = 1920
  53 +props.chartConfig.attr.h = 148
  54 +props.chartConfig.attr.x = 0
  55 +props.chartConfig.attr.y = 0
  56 +
  57 +watch(
  58 + () => props.chartConfig.option,
  59 + (newData: any) => {
  60 + option.configOption = newData
  61 + },
  62 + {
  63 + immediate: true,
  64 + deep: false
  65 + }
  66 +)
  67 +
  68 +useChartDataFetch(props.chartConfig, useChartEditStore, (newData: any) => {
  69 + option.configOption = newData
  70 +})
  71 +
  72 +
  73 +//TODO待封装 这里和原作者时间通用获取当前时间代码一样
  74 +onMounted(() => {
  75 +//格式化当前时间
  76 + timer = setInterval(() => {
  77 + const
  78 + weeks = {
  79 + "0": '星期日',
  80 + "1": '星期一',
  81 + "2": '星期二',
  82 + "3": '星期三',
  83 + "4": '星期四',
  84 + "5": '星期五',
  85 + "6": '星期六',
  86 + }
  87 + const datetime = new Date()
  88 + const year = datetime.getFullYear()
  89 + const month = datetime.getMonth() + 1 < 10 ? '0' + (datetime.getMonth() + 1) : datetime.getMonth() + 1
  90 + const date = datetime.getDate() < 10 ? '0' + datetime.getDate() : datetime.getDate()
  91 + const hh = datetime.getHours() // 时
  92 + const mm = datetime.getMinutes() // 分
  93 + const ss = datetime.getSeconds() // 分
  94 + let weekIndex = datetime.getDay();
  95 + let time = ''
  96 + if (hh < 10) time += '0'
  97 + time += hh + ':'
  98 + if (mm < 10) time += '0'
  99 + time += mm + ':'
  100 + if (ss < 10) time += '0'
  101 + time += ss
  102 + yearMonthDay.value = `${year}-${month}-${date}`
  103 + nowData.value = time
  104 + newData.value = yearMonthDay.value + ' ' + nowData.value + ' ' + weeks[weekIndex]
  105 + }, 500)
  106 +})
  107 +onUnmounted(() => {
  108 + clearInterval(timer)
  109 +})
  110 +
  111 +</script>
  112 +
  113 +<style lang="scss" scoped>
  114 +@include go('text-box') {
  115 + display: flex;
  116 + align-items: center;
  117 + justify-content: center;
  118 + .n-gradient-text {
  119 + white-space: initial;
  120 + }
  121 +}
  122 +
  123 +.light-green {
  124 + height: 108px;
  125 + background-color: rgba(0, 128, 0, 0.12);
  126 +}
  127 +
  128 +.green {
  129 + height: 108px;
  130 + background-color: rgba(0, 128, 0, 0.24);
  131 +}
  132 +
  133 +.go-n-grid {
  134 + background: url(@/assets/images/chart/headbackground/bg_top.png) center no-repeat;
  135 + background-size: 100% 100%;
  136 + text-align: center;
  137 + font-size: 36px;
  138 + line-height: 90px;
  139 +}
  140 +</style>
... ...