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 -}  
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 -}  
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 -}  
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>