@yangyongtao/gaea 1.0.3 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. package/README.md +158 -67
  2. package/package.json +28 -7
  3. package/public/Gaea.apple-touch-icon.png +0 -0
  4. package/public/Gaea.apple-touch-icon.png.import +35 -0
  5. package/public/Gaea.audio.worklet.js +211 -0
  6. package/public/Gaea.html +245 -0
  7. package/public/Gaea.icon.png +0 -0
  8. package/public/Gaea.icon.png.import +35 -0
  9. package/public/Gaea.js +782 -0
  10. package/public/Gaea.png +0 -0
  11. package/public/Gaea.png.import +35 -0
  12. package/public/Gaea.worker.js +1 -0
  13. package/public/GaeaApp.html +275 -0
  14. package/public/GaeaMethods.js +4342 -0
  15. package/public/GaeaModule.html +276 -0
  16. package/public/config.js +76 -0
  17. package/public/constants.js +185 -0
  18. package/public/favicon.ico +0 -0
  19. package/public/image/1.png +0 -0
  20. package/public/image/12-min-min.gif +0 -0
  21. package/public/image/3.png +0 -0
  22. package/public/image/labelImg//345/217/263/350/276/271.png +0 -0
  23. package/public/image/labelImg//345/267/246/350/276/271.png +0 -0
  24. package/public/image/labelImg//346/260/264/344/275/215.png +0 -0
  25. package/public/image/screenIcon//345/205/266/344/273/226.png +0 -0
  26. package/public/image/screenIcon//345/256/211/345/205/250/347/233/221/346/265/213/350/201/232/345/220/210-/347/272/242.png +0 -0
  27. package/public/image/screenIcon//345/256/211/345/205/250/347/233/221/346/265/213/350/201/232/345/220/210-/347/273/277.png +0 -0
  28. package/public/image/screenIcon//346/212/242/351/231/251/345/215/225/344/275/215.png +0 -0
  29. package/public/image/screenIcon//346/226/255/351/235/242.png +0 -0
  30. package/public/image/screenIcon//346/227/240/344/272/272/346/234/272.png +0 -0
  31. package/public/image/screenIcon//346/227/240/344/272/272/346/234/272/345/237/272/345/234/260.png +0 -0
  32. package/public/image/screenIcon//346/260/264/345/272/223/347/253/231.png +0 -0
  33. package/public/image/screenIcon//346/260/264/346/226/207/346/265/213/347/253/231.png +0 -0
  34. package/public/image/screenIcon//346/260/264/351/227/270.png +0 -0
  35. package/public/image/screenIcon//346/262/263/351/201/223/347/253/231-/346/227/240/346/225/260/346/215/256.png +0 -0
  36. package/public/image/screenIcon//346/262/263/351/201/223/347/253/231-/346/255/243/345/270/270.png +0 -0
  37. package/public/image/screenIcon//346/262/263/351/201/223/347/253/231-/350/266/205/344/277/235.png +0 -0
  38. package/public/image/screenIcon//346/262/263/351/201/223/347/253/231-/350/266/205/350/255/246.png +0 -0
  39. package/public/image/screenIcon//346/263/265/347/253/231-/347/201/260.png +0 -0
  40. package/public/image/screenIcon//346/263/265/347/253/231-/347/273/277.png +0 -0
  41. package/public/image/screenIcon//346/265/201/351/207/217/346/265/213/347/253/231.png +0 -0
  42. package/public/image/screenIcon//346/265/267/345/241/230-1/347/272/247.png +0 -0
  43. package/public/image/screenIcon//346/265/267/345/241/230-2/347/272/247.png +0 -0
  44. package/public/image/screenIcon//346/265/267/345/241/230-3/347/272/247.png +0 -0
  45. package/public/image/screenIcon//346/265/267/345/241/230-4/347/272/247.png +0 -0
  46. package/public/image/screenIcon//346/265/267/345/241/230-5/347/272/247.png +0 -0
  47. package/public/image/screenIcon//346/265/267/345/241/230-/346/251/231.png +0 -0
  48. package/public/image/screenIcon//346/265/267/345/241/230-/347/272/242.png +0 -0
  49. package/public/image/screenIcon//346/265/267/345/241/230-/347/273/277.png +0 -0
  50. package/public/image/screenIcon//346/265/267/345/241/230-/350/247/204/346/250/241/344/273/245/344/270/213.png +0 -0
  51. package/public/image/screenIcon//346/265/267/345/241/230-/351/273/204.png +0 -0
  52. package/public/image/screenIcon//346/265/267/345/241/230.png +0 -0
  53. package/public/image/screenIcon//346/275/256/344/275/215.png +0 -0
  54. package/public/image/screenIcon//346/275/256/344/275/215/347/253/231-/346/227/240/346/225/260/346/215/256.png +0 -0
  55. package/public/image/screenIcon//346/275/256/344/275/215/347/253/231-/346/255/243/345/270/270.png +0 -0
  56. package/public/image/screenIcon//346/275/256/344/275/215/347/253/231-/350/266/205/344/277/235.png +0 -0
  57. package/public/image/screenIcon//346/275/256/344/275/215/347/253/231-/350/266/205/350/255/246.png +0 -0
  58. package/public/image/screenIcon//347/211/251/350/265/204/344/273/223/345/272/223.png +0 -0
  59. package/public/image/screenIcon//347/220/203/346/234/272-/345/205/263.png +0 -0
  60. package/public/image/screenIcon//347/220/203/346/234/272-/345/274/200.png +0 -0
  61. package/public/image/screenIcon//347/220/203/346/234/272-/347/272/242.png +0 -0
  62. package/public/image/screenIcon//350/247/206/351/242/221/347/233/221/346/216/247.png +0 -0
  63. package/public/image/screenIcon//351/227/270/351/227/250-/347/201/260.png +0 -0
  64. package/public/image/screenIcon//351/227/270/351/227/250-/347/273/277.png +0 -0
  65. package/public/image/screenIcon//351/230/262/346/264/252/344/273/223/345/272/223.png +0 -0
  66. package/public/image/screenIcon//351/232/220/346/202/243.png +0 -0
  67. package/public/image/screenIcon//351/233/250/351/207/217/347/253/231-/346/265/205/350/223/235.png +0 -0
  68. package/public/image/screenIcon//351/233/250/351/207/217/347/253/231-/347/201/260.png +0 -0
  69. package/public/image/screenIcon//351/233/250/351/207/217/347/253/231-/347/262/211.png +0 -0
  70. package/public/image/screenIcon//351/233/250/351/207/217/347/253/231-/347/272/242.png +0 -0
  71. package/public/image/screenIcon//351/233/250/351/207/217/347/253/231-/347/273/277.png +0 -0
  72. package/public/image/screenIcon//351/233/250/351/207/217/347/253/231-/350/223/235.png +0 -0
  73. package/public/image/screenIcon//351/233/250/351/207/217/347/253/231-/351/273/204.png +0 -0
  74. package/public/image/screenIcon//351/233/250/351/207/217/347/253/231-/351/273/221.png +0 -0
  75. package/public/image/screenIcon//351/243/216/351/200/237.png +0 -0
  76. package/public/image/screenIcon//351/243/216/351/200/237/346/265/213/347/253/231.png +0 -0
  77. package/public/image//346/260/264/346/226/207.gif +0 -0
  78. package/public/image//350/211/262/345/270/246.png +0 -0
  79. package/public/index.html +22 -0
  80. package/public/index.js +185662 -0
  81. package/public/jsWebControl-1.0.0.min.js +31 -0
  82. package/public/jsencrypt.min.js +1 -0
  83. package/public/math/Box2.js +203 -0
  84. package/public/math/Box3.js +532 -0
  85. package/public/math/Color.js +605 -0
  86. package/public/math/ColorManagement.js +74 -0
  87. package/public/math/Cylindrical.js +61 -0
  88. package/public/math/EngineUtils.js +81 -0
  89. package/public/math/Euler.js +315 -0
  90. package/public/math/Frustum.js +162 -0
  91. package/public/math/Interpolant.js +241 -0
  92. package/public/math/Line3.js +115 -0
  93. package/public/math/MathUtils.js +345 -0
  94. package/public/math/Matrix3.js +365 -0
  95. package/public/math/Matrix4.js +858 -0
  96. package/public/math/Plane.js +205 -0
  97. package/public/math/Quaternion.js +724 -0
  98. package/public/math/Ray.js +493 -0
  99. package/public/math/Sphere.js +243 -0
  100. package/public/math/Spherical.js +86 -0
  101. package/public/math/SphericalHarmonics3.js +243 -0
  102. package/public/math/Triangle.js +299 -0
  103. package/public/math/Vector2.js +464 -0
  104. package/public/math/Vector3.js +715 -0
  105. package/public/math/Vector4.js +644 -0
  106. package/public/math/interpolants/CubicInterpolant.js +151 -0
  107. package/public/math/interpolants/DiscreteInterpolant.js +26 -0
  108. package/public/math/interpolants/LinearInterpolant.js +38 -0
  109. package/public/math/interpolants/QuaternionLinearInterpolant.js +39 -0
  110. package/public/static/Cloud.png +0 -0
  111. package/public/static/Global2.jpg +0 -0
  112. package/public/static/css/main.css +170 -0
  113. package/public/static/geojson//346/265/267/345/241/230.geojson +99 -0
  114. package/public/static/img/loading.gif +0 -0
  115. package/public/static/js/app.js +359 -0
  116. package/public/static/js/appcontroller.js +207 -0
  117. package/public/static/js/dist/game.dev.js +137 -0
  118. package/public/static/js/env.js +74 -0
  119. package/public/static/js/event/event.js +107 -0
  120. package/public/static/js/init.js +8 -0
  121. package/public/static/js/initcloudmorph.js +1 -0
  122. package/public/static/js/log.js +35 -0
  123. package/public/static/js/network/ajax.js +29 -0
  124. package/public/static/js/network/rtcp.js +172 -0
  125. package/public/static/js/network/socket.js +106 -0
  126. package/public/web-control.min.js +2 -0
  127. package/scripts/postinstall.mjs +127 -0
  128. package/src/GaeaMethods.js +68 -405
  129. package/src/components/FlyAlongRoute.vue +1 -0
  130. package/src/components/WeatherControl.vue +2 -0
  131. package/src/directives/vDrag.js +70 -0
  132. package/src/index.js +1 -8
  133. package/src/plugin.js +16 -0
  134. package/src/utils.js +10 -21
  135. package/src/vite-plugin.js +117 -0
  136. package/public/static/1111.res +0 -0
  137. package/src/config.js +0 -40
@@ -1,448 +1,111 @@
1
1
  /**
2
2
  * gaea-3dview npm package
3
- *
4
- * 使用前必须在项目 HTML 中加载 Gaea CDN:
5
- * <script src="path/to/Gaea.js"></script>
6
- *
7
- * 配置初始化:
8
- * import { setConfig } from '@your-scope/gaea-3dview';
9
- * setConfig({ serveUrl: '...', serveLocal: '...' });
10
- *
11
- * 使用 GaeaApp:
12
- * import { GaeaApp } from '@your-scope/gaea-3dview';
13
- * const app = new GaeaApp();
14
- * await app.drawPointIcon({ lat: 27.22, lng: 120.45 });
3
+ *
4
+ * 初始化流程:
5
+ * 1. HTML 加载 <script src="/Gaea.js"> → window.Engine 可用
6
+ * 2. import Gaea from '../public/index.js' → window.InstanceMap / NativeCall 等全局变量
7
+ * 3. new window.Engine({...}).startGame({...}) → Godot WASM 启动
8
+ * 4. app.initDefaultEnvironment() 环境初始化
15
9
  */
16
10
 
17
- // ==================== 基础工具函数 ====================
11
+ import Gaea from '../public/index.js';
18
12
 
19
- /** 加载资源到 Gaea */
20
- function loadResource(url, name) {
21
- return new Promise((res, rej) => {
22
- if (!window.Gaea || !window.Gaea.GaeaResourceLoader) {
23
- rej(new Error('Gaea 未初始化,请先加载 Gaea CDN'));
24
- return;
25
- }
26
- window.Gaea.GaeaResourceLoader.Instance.LoadResourceFromUrl1(
27
- url, name,
28
- (code, msg) => {
29
- if (code === 200) res(true);
30
- else { console.warn(`加载资源失败: ${name}`, msg); rej(false); }
31
- }
32
- );
33
- });
34
- }
35
-
36
- /** 获取文件名 */
37
- function getFileName(url) {
38
- return url.split('/').pop().split('?')[0];
39
- }
40
-
41
- /** RGB 字符串转 Gaea Color */
42
- function rgbToGaeaColor(rgb) {
43
- if (typeof rgb !== 'string') return null;
44
- const match = rgb.match(/\((.+?)\)/);
45
- if (!match) return null;
46
- const arr = match[1].split(',').map(Number);
47
- return new window.Gaea.Color(arr[0] / 255, arr[1] / 255, arr[2] / 255, 1);
48
- }
49
13
 
14
+ // ==================== 配置 ====================
50
15
 
51
- // ==================== Gaea 检查 ====================
52
-
53
- function checkGaea() {
54
- const G = window.Gaea;
55
- if (!G || !G.World || !G.World.Instance) {
56
- console.warn('Gaea 尚未加载完毕,请先调用 await GaeaApp.waitForReady()');
57
- return null;
58
- }
59
- return G;
60
- }
61
-
62
- /**
63
- * 等待 Gaea 引擎初始化完毕(轮询 World.Instance)
64
- * @param {number} timeout - 超时毫秒数,默认 30000
65
- * @returns {Promise<boolean>}
66
- */
67
- async function waitForGaea(timeout = 30000) {
68
- if (window.Gaea && window.Gaea.World && window.Gaea.World.Instance) {
69
- return true;
70
- }
71
- const start = Date.now();
72
- return new Promise((resolve) => {
73
- const timer = setInterval(() => {
74
- if (window.Gaea && window.Gaea.World && window.Gaea.World.Instance) {
75
- clearInterval(timer);
76
- resolve(true);
77
- } else if (Date.now() - start > timeout) {
78
- clearInterval(timer);
79
- console.error('Gaea 初始化超时');
80
- resolve(false);
81
- }
82
- }, 200);
83
- });
84
- }
16
+ const defaultConfig = { serveUrl: '', serveLocal: '' };
17
+ const _config = { ...defaultConfig };
85
18
 
19
+ export function setConfig(cfg) { Object.assign(_config, cfg); }
20
+ export function getConfig() { return _config; }
86
21
 
87
- // ==================== GaeaApp 类 ====================
88
22
 
89
- import { Tween, Group, Easing } from '@tweenjs/tween.js';
90
- import config from './config.js';
23
+ // ==================== GaeaApp ====================
91
24
 
92
25
  export class GaeaApp {
93
26
  constructor(options = {}) {
94
- this.config = { ...config, ...options };
95
-
96
- // ---- 飞行相关 ----
97
- this._flyAnimation = null;
98
- this._flyAnimationPlayer = null;
99
- this._flyModelInstance = null;
100
- this._flyEntityView = null;
101
-
102
- // ---- 点标注相关 ----
103
- this._pointIconElements = [];
104
- this._pointIconLoaded = false;
105
-
106
- // ---- 天气相关 ----
107
- this._weatherInited = false;
108
- this._fullScreenQuad = null;
109
- this._sky = null;
110
- this._sun = null;
111
- this._environment = null;
112
- this._defaultSkyMtl = null;
113
- this._rainSkyMtl = null;
114
- this._rainSkyTexture = null;
115
-
116
- // ---- Tween 动画组 ----
117
- this._tweenGroup = new Group();
118
- }
119
-
120
- /**
121
- * 静态方法:等待 Gaea 引擎就绪
122
- * @example await GaeaApp.waitForReady(); // 30s 超时
123
- * @example await GaeaApp.waitForReady(60000); // 自定义超时
124
- */
125
- static waitForReady(timeout) {
126
- return waitForGaea(timeout);
27
+ this._options = options;
28
+ this.layers = [];
29
+ this.tLayers = [];
127
30
  }
128
31
 
129
- // ==================== 点标注 ====================
130
-
131
- /**
132
- * 在指定经纬度放置图标标记
133
- * @param {Object} opts - { lat, lng, alt?, iconSize?, enablePick? }
134
- */
135
- async drawPointIcon(opts = {}) {
136
- const { lat, lng, alt = 0, iconSize = 150, enablePick = true } = opts;
137
- if (lat == null || lng == null) {
138
- console.error('drawPointIcon: lat 和 lng 不能为空');
139
- return null;
140
- }
141
-
142
- const Gaea = checkGaea();
143
- if (!Gaea) return null;
144
- const resName = 'pointIcon.res';
145
-
146
- if (!this._pointIconLoaded) {
147
- const resUrl = `${this.config.serveLocal}/static/1111.res`;
148
- const loaded = await loadResource(resUrl, resName);
149
- if (!loaded) return null;
150
- this._pointIconLoaded = true;
151
- }
152
-
153
- const texId = Gaea.GaeaResourceLoader.Instance.GetResource(resName);
154
- const tex = new Gaea.Texture(false);
155
- tex.InstanceID = texId + '';
32
+ get config() { return { ..._config, ...this._options }; }
156
33
 
157
- const pos = new Gaea.Vector3(lat, lng, alt);
158
- const shape = Gaea.Geometry.Create1(Gaea.GeometryType.Point, [pos]);
34
+ async initDefaultEnvironment() {
35
+ window.Gaea = Gaea;
36
+ Gaea.World.Instance.Is3DTilesNeedCache = false;
37
+ Gaea.World.Instance.IsPyramidTileSetNeedCache = false;
159
38
 
160
- const element = new Gaea.PointGeometryElement();
161
- element.Shape = shape;
39
+ const envRes = 'res://default_env.tres';
40
+ const fogEnv = Gaea.Environment.ConvertBy(Gaea.GaeaResourceLoader.Instance.LoadLoaclResource(envRes));
41
+ fogEnv.FogEnabled = false;
162
42
 
163
- const iconSymbol = new Gaea.IconMarkSymbol();
164
- iconSymbol.MarkSize = iconSize;
165
- iconSymbol.Icon = tex;
166
- element.Symbol = iconSymbol;
167
- element.EnablePick = enablePick;
168
- element.EnableEdit = false;
43
+ Gaea.World.Instance.EngineConfigString =
44
+ `[Engine]\nDefaultGlobalOverview="Global2.jpg"\nAssetHost="${this.config.serveLocal}"`;
169
45
 
170
- Gaea.World.Instance.RenderableObjectList.AddLast(element);
171
- this._pointIconElements.push(element);
172
- return element;
173
- }
46
+ const env = Gaea.Environment.ConvertBy(Gaea.GaeaResourceLoader.Instance.LoadLoaclResource(envRes));
47
+ env.BackgroundEnergy = 0.6;
174
48
 
175
- /**
176
- * 批量添加图标标记
177
- * @param {Array} pointList - [{ lat, lng, alt?, iconSize? }]
178
- */
179
- async drawPointIcons(pointList = []) {
180
- const elements = [];
181
- for (const p of pointList) {
182
- const el = await this.drawPointIcon(p);
183
- if (el) elements.push(el);
184
- }
185
- return elements;
186
- }
49
+ const sun = Gaea.Sun.ConvertBy(Gaea.World.Instance.GetNode('Sun'));
50
+ sun.Power = 1.5;
187
51
 
188
- /** 清除所有点标注 */
189
- clearPointIcons() {
190
- const Gaea = window.Gaea;
191
- this._pointIconElements.forEach(el => {
192
- Gaea.World.Instance.RenderableObjectList.Remove(el);
193
- });
194
- this._pointIconElements = [];
52
+ Gaea.World.Instance.ForceCloudVisalbe = true;
53
+ Gaea.World.Instance.CloudVisalbe = false;
195
54
  }
196
55
 
197
- // ==================== 沿线飞行 ====================
198
-
199
- /**
200
- * 沿路径飞行
201
- * @param {Array} lineData - [{ x: lat, y: lng }, ...]
202
- * @param {Object} opts - { height, step, duration, xrotation, lockEye, minZoom, maxZoom }
203
- */
204
- async flyAlongPath(lineData, opts = {}) {
205
- const Gaea = checkGaea();
206
- if (!Gaea) return Promise.reject(new Error('Gaea 未加载'));
207
- const {
208
- height = 150, step = 1000, duration = 20,
209
- xrotation = -30, lockEye = true, minZoom = 0, maxZoom = 400
210
- } = opts;
211
-
212
- if (!lineData || lineData.length < 2) {
213
- return Promise.reject(new Error('至少需要2个路径点'));
214
- }
215
-
56
+ async getAllServe() {
57
+ const cfg = this.config;
58
+ const url = `${cfg.serveUrl}htc/service/wmts?REQUEST=GetCapabilities`;
216
59
  try {
217
- this._cleanupFlyResources();
218
-
219
- const bezier = new Gaea.UniformCubicSpline();
220
- for (let i = 0; i < lineData.length; i++) {
221
- const ctrl = Gaea.GaeaMath.SphericalToCartesianDeg(
222
- new Gaea.Vector3(lineData[i].x, lineData[i].y, height)
223
- );
224
- bezier.AddValue(i, ctrl);
225
- }
226
- bezier.Step = step;
227
- bezier.Interpolate(true);
228
- bezier.CalculateLengthAfterInterpolation();
229
-
230
- const startPos = Gaea.GaeaMath.SphericalToCartesianDeg(
231
- new Gaea.Vector3(lineData[0].x, lineData[0].y, height)
232
- );
233
-
234
- const mesh = new Gaea.CubeMesh();
235
- mesh.Size = new Gaea.Vector3(1, 1, 1);
236
- const mtl = new Gaea.SpatialMaterial();
237
- mtl.AlbedoColor = new Gaea.Color(1, 0, 0, 1);
238
- mesh.SurfaceSetMaterial(0, mtl);
239
-
240
- this._flyModelInstance = new Gaea.MeshInstance();
241
- this._flyModelInstance.Name = 'flyModel';
242
- this._flyModelInstance.Visible = false;
243
- this._flyModelInstance.Translation = startPos;
244
- Gaea.World.Instance.AddChild(this._flyModelInstance, false);
245
-
246
- this._flyEntityView = new Gaea.EntityView();
247
- this._flyEntityView.Offset3D = new Gaea.Vector3(
248
- -1, 0, Math.tan(xrotation / 180 * Math.PI)
249
- );
250
- this._flyEntityView.LockEye = lockEye;
251
- this._flyEntityView.MinMaxZoom3D = new Gaea.Vector2(minZoom, maxZoom);
252
- this._flyEntityView.Init(this._flyModelInstance);
253
- Gaea.World.Instance.CameraController.LockedEntity = this._flyEntityView;
254
-
255
- this._flyAnimation = bezier.ToAnimationByTime(
256
- 'flyAnim', true, duration, new Gaea.Vector3(1, 1, 1)
257
- );
258
- this._flyAnimation.TrackSetPath(0, '/root/World/flyModel');
259
-
260
- this._flyAnimationPlayer = new Gaea.GaeaAnimationPlayer();
261
- this._flyAnimationPlayer.AddAnimation('flyAnim', this._flyAnimation);
262
- Gaea.World.Instance.AddChild(this._flyAnimationPlayer, false);
263
-
264
- return new Promise((resolve) => {
265
- this._flyAnimationPlayer.PlayWithCallback(
266
- 'flyAnim', Gaea.CallbackType.AnimatioFinished, () => resolve()
267
- );
268
- });
60
+ const xml = await (await fetch(url)).text();
61
+ const hostUrl = `${cfg.serveUrl}htc/service/wmts`;
62
+ const layers = Gaea.WMTSImageStore.ParserXml2Capabilities(hostUrl, xml);
63
+ this.layers = [...this.layers, ...(layers || [])];
269
64
  } catch (e) {
270
- this._cleanupFlyResources();
271
- return Promise.reject(e);
65
+ console.warn('getAllServe 失败:', e.message);
272
66
  }
67
+ return this.layers;
273
68
  }
274
69
 
275
- /** 停止飞行 */
276
- stopFlyAlongPath() {
277
- try {
278
- if (this._flyAnimationPlayer) {
279
- this._flyAnimationPlayer.Stop('flyAnim');
280
- }
281
- } catch (e) { /* ignore */ }
282
- this._cleanupFlyResources();
283
- }
284
-
285
- _cleanupFlyResources() {
286
- const Gaea = window.Gaea;
287
- try {
288
- if (this._flyAnimationPlayer) {
289
- Gaea.World.Instance.RemoveChild(this._flyAnimationPlayer);
290
- this._flyAnimationPlayer = null;
291
- }
292
- this._flyEntityView = null;
293
- if (this._flyModelInstance) {
294
- Gaea.World.Instance.RemoveChild(this._flyModelInstance);
295
- this._flyModelInstance = null;
296
- }
297
- Gaea.World.Instance.CameraController.LockedEntity = null;
298
- this._flyAnimation = null;
299
- } catch (e) { /* ignore */ }
300
- }
301
-
302
- /** 重置相机视角 */
303
- cameraReset() {
304
- const Gaea = window.Gaea;
305
- const camera = Gaea.World.Instance.DefaultCamera;
306
- camera && camera.Reset();
307
- }
308
-
309
- // ==================== 天气控制 ====================
310
-
311
- _initWeather() {
312
- if (this._weatherInited) return;
313
- const Gaea = window.Gaea;
314
- if (!Gaea || !Gaea.World || !Gaea.World.Instance) {
315
- console.warn('Gaea 尚未加载完毕,无法初始化天气');
316
- return;
317
- }
318
- this._fullScreenQuad = Gaea.World.Instance.FullScreenQuad;
319
- this._sky = Gaea.MeshInstance.ConvertBy(Gaea.World.Instance.GetNode('Sky'));
320
- this._sun = Gaea.Sun.ConvertBy(Gaea.World.Instance.GetNode('Sun'));
321
- this._environment = Gaea.Environment.ConvertBy(
322
- Gaea.GaeaResourceLoader.Instance.LoadLoaclResource('res://default_env.tres')
323
- );
324
- this._defaultSkyMtl = this._sky.MaterialOverride;
325
- this._weatherInited = true;
326
- }
70
+ addLayer({ layerName, max, min, transparency, forMat = 'image/vnd.jpeg-png', inserIndex = null } = {}) {
71
+ const mime = ['image/jpeg','image/png','image/tga','image/webp','image/bmp','application/json;type=geojson','image/vnd.jpeg-png'];
72
+ const mimeIdx = mime.indexOf(forMat);
73
+ if (mimeIdx === -1) return console.warn('未知图层类型:', forMat);
327
74
 
328
- /** 开启下雨 */
329
- enableRain(params = {}) {
330
- this._initWeather();
331
- const Gaea = window.Gaea;
332
- const fsq = this._fullScreenQuad;
333
- if (!fsq) return;
75
+ if (!this.layers?.length) return console.warn('图层列表为空,请先调用 getAllServe()');
334
76
 
335
- const {
336
- direction = 0, speed = 5, count = 30
337
- } = params;
77
+ const capability = this.layers.find(i => i.Title === layerName);
78
+ if (!capability) return console.warn(`图层 "${layerName}" 未找到`);
338
79
 
339
- fsq.Visible = true;
340
- fsq.NeedAtmosphere = true;
80
+ const store = new Gaea.WMTSImageStore();
81
+ store.ImageExtension = mimeIdx;
82
+ store.CurrentCapabilitie = capability;
341
83
 
342
- this._sun.TimeString = '2022-09-15 00:00:00';
343
- this._sun.LightColor = new Gaea.Color(1, 1, 1, 1);
344
- this._sun.LightEnergy = 0.05;
345
- this._environment.BackgroundEnergy = 0.11;
346
- this._environment.GlowBlendMode = 1;
84
+ if (max !== undefined) store.LevelRange = new Gaea.Vector2(min, max);
85
+ if (transparency !== undefined) store.ImageTransparency = transparency;
347
86
 
348
- fsq.RainyCount = count;
349
- fsq.Speed = speed;
350
- fsq.WindDirection = direction;
351
- fsq.Rainy = true;
352
- }
87
+ if (!store.CurrentCapabilitie.InstanceID) return console.error(`${layerName} 加载异常`);
353
88
 
354
- /** 更新雨参数 */
355
- updateRain(params = {}) {
356
- const Gaea = window.Gaea;
357
- const fsq = this._fullScreenQuad;
358
- if (!fsq) return;
359
- if (params.direction !== undefined) fsq.WindDirection = params.direction;
360
- if (params.speed !== undefined) fsq.Speed = params.speed;
361
- if (params.count !== undefined) fsq.RainyCount = params.count;
89
+ const tileset = Gaea.World.Instance.DefaultPyramidTileSet;
90
+ inserIndex !== null ? tileset.InsertImageStore(store, inserIndex) : tileset.AddImageStore(store);
91
+ console.log(`影像 "${layerName}" 添加成功`);
92
+ return store;
362
93
  }
363
94
 
364
- /** 恢复正常天气 */
365
- restoreNormalWeather() {
366
- this._initWeather();
367
- const Gaea = window.Gaea;
368
- const fsq = this._fullScreenQuad;
369
- if (!fsq) return;
370
-
371
- fsq.Rainy = false;
372
- fsq.Visible = false;
373
- fsq.NeedAtmosphere = false;
374
-
375
- this._sun.TimeString = '2022-09-15 12:00:00';
376
- this._sun.LightColor = new Gaea.Color(1, 226 / 255, 164 / 255, 1);
377
- this._sun.LightEnergy = 3.5;
378
- this._environment.BackgroundEnergy = 0.2;
379
- this._environment.GlowBlendMode = 2;
380
-
381
- if (this._defaultSkyMtl && this._sky) {
382
- this._sky.MaterialOverride = this._defaultSkyMtl;
383
- }
384
- }
385
-
386
- /** 初始化基础环境(关闭默认雾、设置默认光照等) */
387
- async initDefaultEnvironment() {
388
- // 等待 Gaea 就绪
389
- const ready = await waitForGaea(15000);
390
- if (!ready) {
391
- console.error('Gaea 引擎初始化超时');
392
- return;
393
- }
394
-
395
- const Gaea = window.Gaea;
396
-
397
- // 关闭默认雾
398
- const fogEnv = Gaea.Environment.ConvertBy(
399
- Gaea.GaeaResourceLoader.Instance.LoadLoaclResource('res://default_env.tres')
400
- );
401
- fogEnv.FogEnabled = false;
402
-
403
- // 基础环境光
404
- const env = Gaea.Environment.ConvertBy(
405
- Gaea.GaeaResourceLoader.Instance.LoadLoaclResource('res://default_env.tres')
406
- );
407
- env.BackgroundEnergy = 0.6;
408
-
409
- const sun = Gaea.Sun.ConvertBy(Gaea.World.Instance.GetNode('Sun'));
410
- sun.Power = 1.5;
411
-
412
- Gaea.World.Instance.ForceCloudVisalbe = true;
413
- Gaea.World.Instance.CloudVisalbe = false;
414
-
415
- window.Gaea = Gaea;
416
- }
417
-
418
- /** 设置静止资源 Base URL */
419
- setAssetHost(assetHost) {
420
- const Gaea = window.Gaea;
421
- const cfg = `[Engine]\nDefaultGlobalOverview="Global2.jpg"\nAssetHost="${assetHost}"`;
422
- Gaea.World.Instance.EngineConfigString = cfg;
423
- }
424
-
425
- // ==================== 工具方法 ====================
426
-
427
- /** 屏幕坐标 → 经纬度 */
428
- screenToLatLng(event) {
429
- const Gaea = window.Gaea;
430
- if (!Gaea || !Gaea.GaeaMath) return null;
431
- const result = Gaea.GaeaMath.ProjectPosition(
432
- new Gaea.Vector2(event.offsetX, event.offsetY)
433
- );
434
- const lonlat = Gaea.GaeaMath.CartesianToSphericalDeg(result);
435
- return { lat: lonlat.x, lng: lonlat.y, alt: lonlat.z };
95
+ /** 定位到指定视角(经纬度高程 + 相机参数) */
96
+ SetPosition(numStr) {
97
+ const arr = numStr.split(',').map(s => Number(s.trim()));
98
+ Gaea.World.Instance.DefaultCamera.SetPosition2(arr[0], arr[1], arr[2], arr[3], arr[4], arr[5]);
436
99
  }
437
100
 
438
- /** Vector3 快捷创建 */
439
- vec3(x = 0, y = 0, z = 0) {
440
- return new window.Gaea.Vector3(x, y, z);
101
+ /** 记录当前视角,返回 URI 字符串 */
102
+ favorite() {
103
+ return Gaea.GaeaCamera.ConvertBy(Gaea.World.Instance.DefaultCamera).Favorite();
441
104
  }
442
105
 
443
- /** Color 快捷创建 (0-1) */
444
- color(r, g, b, a = 1) {
445
- return new window.Gaea.Color(r, g, b, a);
106
+ /** 定位到已记录的视角 URI */
107
+ favoritePosition(uri) {
108
+ Gaea.World.Instance.DefaultCamera.GotoFavorite(uri);
446
109
  }
447
110
  }
448
111
 
@@ -89,6 +89,7 @@
89
89
  <script setup>
90
90
  import { ref, onBeforeUnmount } from 'vue';
91
91
  import { GaeaApp } from '../GaeaMethods.js';
92
+ import vDrag from '../directives/vDrag.js';
92
93
 
93
94
  const props = defineProps({
94
95
  appInstance: { type: Object, default: null }
@@ -80,6 +80,8 @@
80
80
  <script setup>
81
81
  import { ref, onBeforeUnmount } from 'vue';
82
82
  import { GaeaApp } from '../GaeaMethods.js';
83
+ // v-drag 指令:import 后自动在 template 中可用
84
+ import vDrag from '../directives/vDrag.js';
83
85
 
84
86
  const props = defineProps({
85
87
  appInstance: { type: Object, default: null }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * v-drag 指令 - 使元素可拖拽
3
+ * 用法:<div v-drag>...</div>
4
+ * 拖拽触发热区需要有 class "title"
5
+ */
6
+ export default {
7
+ mounted(el) {
8
+ let dragging = false;
9
+ let startX = 0, startY = 0;
10
+ let initialLeft = 0, initialTop = 0;
11
+ const originalTransition = el.style.transition;
12
+ const minTop = 60;
13
+ let maxLeft = 0, maxTop = 0;
14
+
15
+ const clamp = (val, min, max) => Math.max(min, Math.min(val, max));
16
+
17
+ const init = () => {
18
+ maxLeft = window.innerWidth - el.offsetWidth;
19
+ maxTop = window.innerHeight - el.offsetHeight;
20
+ const rect = el.getBoundingClientRect();
21
+ el.style.left = `${clamp(rect.left, 0, maxLeft)}px`;
22
+ el.style.top = `${clamp(rect.top, minTop, maxTop)}px`;
23
+ el.style.userSelect = 'none';
24
+ el.style.pointerEvents = 'auto';
25
+ };
26
+
27
+ init();
28
+
29
+ el._vDragMouseDown = (event) => {
30
+ const isTitleBar = event.target.classList.contains('title')
31
+ || event.target.closest('.title');
32
+ if (!isTitleBar) return;
33
+
34
+ event.preventDefault();
35
+ el.style.transition = 'none';
36
+ dragging = true;
37
+ startX = event.clientX;
38
+ startY = event.clientY;
39
+ const rect = el.getBoundingClientRect();
40
+ initialLeft = rect.left;
41
+ initialTop = rect.top;
42
+
43
+ window.addEventListener('mousemove', el._vDragMouseMove);
44
+ window.addEventListener('mouseup', el._vDragMouseUp);
45
+ };
46
+
47
+ el._vDragMouseMove = (event) => {
48
+ if (!dragging) return;
49
+ const newLeft = initialLeft + (event.clientX - startX);
50
+ const newTop = initialTop + (event.clientY - startY);
51
+ el.style.left = `${clamp(newLeft, 0, maxLeft)}px`;
52
+ el.style.top = `${clamp(newTop, minTop, maxTop)}px`;
53
+ };
54
+
55
+ el._vDragMouseUp = () => {
56
+ dragging = false;
57
+ el.style.transition = originalTransition;
58
+ window.removeEventListener('mousemove', el._vDragMouseMove);
59
+ window.removeEventListener('mouseup', el._vDragMouseUp);
60
+ };
61
+
62
+ el.addEventListener('mousedown', el._vDragMouseDown);
63
+ },
64
+
65
+ unmounted(el) {
66
+ el.removeEventListener('mousedown', el._vDragMouseDown);
67
+ window.removeEventListener('mousemove', el._vDragMouseMove);
68
+ window.removeEventListener('mouseup', el._vDragMouseUp);
69
+ }
70
+ };
package/src/index.js CHANGED
@@ -2,13 +2,6 @@
2
2
  * gaea-3dview 主入口
3
3
  */
4
4
 
5
- // 配置
6
- export { setConfig, getConfig } from './config.js';
7
- export { default as config } from './config.js';
8
-
9
- // 核心类
5
+ export { setConfig, getConfig } from './GaeaMethods.js';
10
6
  export { GaeaApp } from './GaeaMethods.js';
11
7
  export { default } from './GaeaMethods.js';
12
-
13
- // 工具函数
14
- export { screenToLatLng, loadResource } from './utils.js';
package/src/plugin.js ADDED
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Gaea 3DView Vue 插件
3
+ * 自动注册 v-drag 指令
4
+ */
5
+ import vDrag from './directives/vDrag.js';
6
+
7
+ const GaeaPlugin = {
8
+ install(app) {
9
+ app.directive('drag', vDrag);
10
+ }
11
+ };
12
+
13
+ export default GaeaPlugin;
14
+
15
+ // 同时导出 Vite 插件
16
+ export { default as gaeaVitePlugin } from './vite-plugin.js';
package/src/utils.js CHANGED
@@ -1,30 +1,19 @@
1
- /**
2
- * 工具函数
3
- */
1
+ import Gaea from '../public/index.js';
4
2
 
5
3
  /** 从URL加载资源到Gaea */
6
4
  export function loadResource(url, name) {
7
5
  return new Promise((res, rej) => {
8
- if (!window.Gaea || !window.Gaea.GaeaResourceLoader) {
9
- rej(new Error('Gaea 未初始化'));
10
- return;
11
- }
12
- window.Gaea.GaeaResourceLoader.Instance.LoadResourceFromUrl1(
13
- url, name,
14
- (code, msg) => {
15
- if (code === 200) res(true);
16
- else rej(new Error(msg));
17
- }
6
+ if (!Gaea?.GaeaResourceLoader) return rej(new Error('Gaea 未初始化'));
7
+ Gaea.GaeaResourceLoader.Instance.LoadResourceFromUrl1(url, name,
8
+ (code, msg) => code === 200 ? res(true) : rej(new Error(msg))
18
9
  );
19
10
  });
20
11
  }
21
12
 
22
- /** 屏幕坐标 → 经纬度 (lat: x, lng: y) */
23
- export function screenToLatLng(event) {
24
- if (!window.Gaea || !window.Gaea.GaeaMath) return null;
25
- const result = window.Gaea.GaeaMath.ProjectPosition(
26
- new window.Gaea.Vector2(event.offsetX, event.offsetY)
27
- );
28
- const lonlat = window.Gaea.GaeaMath.CartesianToSphericalDeg(result);
29
- return { lat: lonlat.x, lng: lonlat.y, alt: lonlat.z };
13
+ /** 屏幕坐标 → 经纬度 */
14
+ export function screenToLatLng(e) {
15
+ if (!Gaea?.GaeaMath) return null;
16
+ const r = Gaea.GaeaMath.ProjectPosition(new Gaea.Vector2(e.offsetX, e.offsetY));
17
+ const ll = Gaea.GaeaMath.CartesianToSphericalDeg(r);
18
+ return { lat: ll.x, lng: ll.y, alt: ll.z };
30
19
  }