babyeditor-tool 0.0.7 → 0.0.10

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.
@@ -1,32 +1,704 @@
1
- import { ImportMeshAsync, Node, Mesh, Engine, Scene, Vector3, HavokPlugin, AppendSceneAsync, FreeCamera } from "@babylonjs/core";
2
- import "@babylonjs/materials";
1
+ import { TransformNode, MeshBuilder, StandardMaterial, Color3, Texture, HDRCubeTexture, ArcRotateCamera, ImportMeshAsync, Node, AbstractMesh, Observable, Engine, Scene, PointerEventTypes, Vector3, HavokPlugin, AppendSceneAsync, FreeCamera, QuadraticEase, EasingFunction, TargetCamera } from "@babylonjs/core";
2
+ import { GridMaterial } from "@babylonjs/materials";
3
3
  import "@babylonjs/loaders";
4
4
  import "@babylonjs/post-processes";
5
5
  import "@babylonjs/procedural-textures";
6
6
  import HavokPhysics from "@babylonjs/havok";
7
+ var __defProp$6 = Object.defineProperty;
8
+ var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
+ var __publicField$6 = (obj, key, value) => __defNormalProp$6(obj, typeof key !== "symbol" ? key + "" : key, value);
10
+ const _Projection = class _Projection2 {
11
+ /**
12
+ * 投影坐标转换
13
+ * @param from 原始坐标系
14
+ * @param to 投影坐标系
15
+ * @param coordinates 坐标
16
+ * @returns 转换后的坐标
17
+ */
18
+ static Transform(from, to, coordinates) {
19
+ if (from === to) {
20
+ return coordinates;
21
+ }
22
+ if (from === _Projection2.EPSG4326 && to === _Projection2.EPSG3857) {
23
+ return this.EPSG4326To3857(coordinates);
24
+ }
25
+ if (from === _Projection2.EPSG3857 && to === _Projection2.EPSG4326) {
26
+ return this.EPSG3857To4326(coordinates);
27
+ }
28
+ throw new Error(`Unsupported projection transformation: ${from} to ${to}`);
29
+ }
30
+ /**
31
+ * EPSG:4326转EPSG:3857
32
+ * @param coordinates 坐标
33
+ * @returns 转换后的坐标
34
+ */
35
+ static EPSG4326To3857(coordinates) {
36
+ const lat = Math.max(-this.MAX_LATITUDE, Math.min(this.MAX_LATITUDE, coordinates[1]));
37
+ const lng = Math.max(-180, Math.min(180, coordinates[0]));
38
+ const latRad = lat * Math.PI / 180;
39
+ const lngRad = lng * Math.PI / 180;
40
+ const x = this.R * lngRad;
41
+ const y = this.R * Math.log(Math.tan(Math.PI / 4 + latRad / 2));
42
+ const clampedX = Math.max(-this.MAX_PROJECTED_COORD, Math.min(this.MAX_PROJECTED_COORD, x));
43
+ const clampedY = Math.max(-this.MAX_PROJECTED_COORD, Math.min(this.MAX_PROJECTED_COORD, y));
44
+ return [clampedX, clampedY];
45
+ }
46
+ /**
47
+ * EPSG:3857转EPSG:4326
48
+ * @param coordinates 坐标
49
+ * @returns 转换后的坐标
50
+ */
51
+ static EPSG3857To4326(coordinates) {
52
+ const x = Math.max(-this.MAX_PROJECTED_COORD, Math.min(this.MAX_PROJECTED_COORD, coordinates[0]));
53
+ const y = Math.max(-this.MAX_PROJECTED_COORD, Math.min(this.MAX_PROJECTED_COORD, coordinates[1]));
54
+ const lng = x / this.R * 180 / Math.PI;
55
+ const latRad = 2 * Math.atan(Math.exp(y / this.R)) - Math.PI / 2;
56
+ const lat = latRad * 180 / Math.PI;
57
+ return [lng, lat];
58
+ }
59
+ };
60
+ __publicField$6(_Projection, "R", 6378137);
61
+ __publicField$6(_Projection, "R_MINOR", 6356752314245179e-9);
62
+ __publicField$6(_Projection, "MAX_LATITUDE", 85.0511287798);
63
+ __publicField$6(_Projection, "MAX_PROJECTED_COORD", _Projection.R * Math.PI);
64
+ __publicField$6(_Projection, "EPSG4326", "EPSG:4326");
65
+ __publicField$6(_Projection, "EPSG3857", "EPSG:3857");
66
+ __publicField$6(_Projection, "Max3857BBox", [-20037508342789244e-9, -2003750833989489e-8, 20037508342789244e-9, 2003750833989489e-8]);
67
+ __publicField$6(_Projection, "Max4326BBox", [-180, -90, 180, 90]);
68
+ let Projection = _Projection;
69
+ var __defProp$5 = Object.defineProperty;
70
+ var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
71
+ var __publicField$5 = (obj, key, value) => __defNormalProp$5(obj, typeof key !== "symbol" ? key + "" : key, value);
72
+ class Layer {
73
+ constructor(name, scene) {
74
+ __publicField$5(this, "layerRootNode");
75
+ __publicField$5(this, "name", "");
76
+ this.name = name;
77
+ this.layerRootNode = new TransformNode(name, scene);
78
+ this.layerRootNode.name = name;
79
+ this.layerRootNode.metadata = { editable: false, layerName: name };
80
+ }
81
+ /**
82
+ * 获取图层是否启用
83
+ */
84
+ get isEnabled() {
85
+ return this.layerRootNode.isEnabled();
86
+ }
87
+ /**
88
+ * 设置图层是否启用
89
+ * @param enabled 是否启用
90
+ */
91
+ set isEnabled(enabled) {
92
+ this.layerRootNode.setEnabled(enabled);
93
+ }
94
+ /**
95
+ * 当图层启用状态改变时触发
96
+ * @param observers 观察者
97
+ */
98
+ get onEnabledStateChanged() {
99
+ return this.layerRootNode.onEnabledStateChangedObservable;
100
+ }
101
+ /**
102
+ * 设置图层是否启用
103
+ * @param enabled 是否启用
104
+ */
105
+ setEnabled(enabled) {
106
+ this.layerRootNode.setEnabled(enabled);
107
+ }
108
+ /**
109
+ * 释放图层
110
+ */
111
+ dispose() {
112
+ this.layerRootNode.dispose();
113
+ }
114
+ onDisposeObservable(observers) {
115
+ return this.layerRootNode.onDisposeObservable.add(observers);
116
+ }
117
+ }
118
+ var __defProp$4 = Object.defineProperty;
119
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
120
+ var __publicField$4 = (obj, key, value) => __defNormalProp$4(obj, typeof key !== "symbol" ? key + "" : key, value);
121
+ class TileLayer {
122
+ constructor(name, url) {
123
+ __publicField$4(this, "name", "");
124
+ __publicField$4(this, "url", "");
125
+ __publicField$4(this, "bbox", [0, 0, 0, 0]);
126
+ this.name = name;
127
+ this.url = url;
128
+ }
129
+ getTileUrl(x, y, z) {
130
+ return this.url.replace("{z}", z.toString()).replace("{x}", x.toString()).replace("{y}", y.toString());
131
+ }
132
+ requestImage(x, y, z) {
133
+ const url = this.getTileUrl(x, y, z);
134
+ const image = new Image();
135
+ image.crossOrigin = "anonymous";
136
+ image.src = url;
137
+ return new Promise((resolve, reject) => {
138
+ image.onload = () => resolve(image);
139
+ image.onerror = () => reject(new Error("Failed to load image"));
140
+ });
141
+ }
142
+ }
143
+ var __defProp$3 = Object.defineProperty;
144
+ var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
145
+ var __publicField$3 = (obj, key, value) => __defNormalProp$3(obj, typeof key !== "symbol" ? key + "" : key, value);
146
+ class TileLayerRenderer extends Layer {
147
+ /**
148
+ * 构造函数
149
+ * @param mapViewer 地图视图
150
+ */
151
+ constructor(mapViewer) {
152
+ super("TileLayerRenderer", mapViewer.scene);
153
+ __publicField$3(this, "tileLayers", []);
154
+ __publicField$3(this, "mapViewer");
155
+ __publicField$3(this, "maxBBox");
156
+ __publicField$3(this, "currentZoom", 1);
157
+ __publicField$3(this, "renderedTiles", /* @__PURE__ */ new Map());
158
+ __publicField$3(this, "cameraObserver", null);
159
+ __publicField$3(this, "autoUpdate", false);
160
+ this.mapViewer = mapViewer;
161
+ this.maxBBox = mapViewer.projection === "EPSG:3857" ? Projection.Max3857BBox : Projection.Max4326BBox;
162
+ this.layerRootNode.parent = mapViewer.rootNode;
163
+ this.tileLayers = [new TileLayer("aaa", "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}")];
164
+ }
165
+ get projectionBBox() {
166
+ return this.mapViewer.getProjectionBbox();
167
+ }
168
+ /**
169
+ * 获取地图范围
170
+ * @returns [minX, minY, maxX, maxY] 地图范围
171
+ */
172
+ get bbox() {
173
+ return this.mapViewer.bbox;
174
+ }
175
+ /**
176
+ * 获取地图大小
177
+ * @returns [width, height] 地图大小
178
+ */
179
+ get size() {
180
+ return this.mapViewer.size;
181
+ }
182
+ /**
183
+ * 获取地图投影
184
+ * @returns 地图投影
185
+ */
186
+ get projection() {
187
+ return this.mapViewer.projection;
188
+ }
189
+ /**
190
+ * 根据地图投影坐标和缩放级别获取瓦片序号
191
+ * @param x 投影坐标X
192
+ * @param y 投影坐标Y
193
+ * @param z 缩放级别
194
+ * @returns [tileX, tileY] 瓦片序号
195
+ */
196
+ positionToTile(x, y, z) {
197
+ const [bboxMinX, bboxMinY, bboxMaxX, bboxMaxY] = this.maxBBox;
198
+ const width = bboxMaxX - bboxMinX;
199
+ const height = bboxMaxY - bboxMinY;
200
+ const tileCount = Math.pow(2, z);
201
+ const tileWidth = width / tileCount;
202
+ const tileHeight = height / tileCount;
203
+ const tileX = Math.floor((x - bboxMinX) / tileWidth);
204
+ const tileY = Math.floor((bboxMaxY - y) / tileHeight);
205
+ return [tileX, tileY];
206
+ }
207
+ /**
208
+ * 根据瓦片序号和缩放级别获取瓦片范围
209
+ * @param tileX 瓦片序号X
210
+ * @param tileY 瓦片序号Y
211
+ * @param z 缩放级别
212
+ * @returns [minX, minY, maxX, maxY] 瓦片范围
213
+ */
214
+ tileToBBox(tileX, tileY, z) {
215
+ const [minX, minY, maxX, maxY] = this.maxBBox;
216
+ const width = maxX - minX;
217
+ const height = maxY - minY;
218
+ const tileCount = Math.pow(2, z);
219
+ const tileWidth = width / tileCount;
220
+ const tileHeight = height / tileCount;
221
+ const tileMinX = minX + tileX * tileWidth;
222
+ const tileMinY = maxY - tileY * tileHeight - tileHeight;
223
+ const tileMaxX = tileMinX + tileWidth;
224
+ const tileMaxY = tileMinY + tileHeight;
225
+ return [tileMinX, tileMaxY, tileMaxX, tileMinY];
226
+ }
227
+ /**
228
+ * 根据瓦片序号和缩放级别获取瓦片中心点坐标
229
+ * @param tileX 瓦片序号X
230
+ * @param tileY 瓦片序号Y
231
+ * @param z 缩放级别
232
+ * @returns [centerX, centerY] 瓦片中心点坐标
233
+ */
234
+ tileToCenter(tileX, tileY, z) {
235
+ const [minX, minY, maxX, maxY] = this.tileToBBox(tileX, tileY, z);
236
+ const centerX = (minX + maxX) / 2;
237
+ const centerY = (minY + maxY) / 2;
238
+ return [centerX, centerY];
239
+ }
240
+ /**
241
+ * 根据瓦片序号和缩放级别获取瓦片在视野中的尺寸大小
242
+ * @param tileX 瓦片序号X
243
+ * @param tileY 瓦片序号Y
244
+ * @param z 缩放级别
245
+ * @returns [width, height] 瓦片在视野中的宽度和高度(像素)
246
+ */
247
+ tileToViewportSize(tileX, tileY, z) {
248
+ const [minX, minY, maxX, maxY] = this.tileToBBox(tileX, tileY, z);
249
+ const [viewportMinX, viewportMinY] = this.projectionToViewport(minX, maxY);
250
+ const [viewportMaxX, viewportMaxY] = this.projectionToViewport(maxX, minY);
251
+ const viewportWidth = Math.abs(viewportMaxX - viewportMinX);
252
+ const viewportHeight = Math.abs(viewportMaxY - viewportMinY);
253
+ return [viewportWidth, viewportHeight];
254
+ }
255
+ /**
256
+ * 将投影坐标转换为地图视野相对坐标
257
+ * @param x 投影坐标X
258
+ * @param y 投影坐标Y
259
+ * @returns [relativeX, relativeY] 相对于地图视野的坐标
260
+ */
261
+ projectionToViewport(x, y) {
262
+ const [bboxMinX, bboxMinY, bboxMaxX, bboxMaxY] = this.projectionBBox;
263
+ const [width, height] = this.size;
264
+ const relativeX = (x - bboxMinX) / (bboxMaxX - bboxMinX);
265
+ const relativeY = (y - bboxMinY) / (bboxMaxY - bboxMinY);
266
+ const viewportX = relativeX * width - this.size[0] / 2;
267
+ const viewportY = relativeY * height - this.size[1] / 2;
268
+ return [viewportX, viewportY];
269
+ }
270
+ /**
271
+ * 根据瓦片序号和缩放级别获取瓦片网格
272
+ * @param tileX 瓦片序号X
273
+ * @param tileY 瓦片序号Y
274
+ * @param z 缩放级别
275
+ * @returns 瓦片网格
276
+ */
277
+ getTileMesh(tileX, tileY, z) {
278
+ const tileMesh = MeshBuilder.CreateGround(`tile-${tileX}-${tileY}-${z}`, { width: 1, height: 1 }, this.mapViewer.scene);
279
+ const center = this.tileToCenter(tileX, tileY, z);
280
+ const worldPosition = this.projectionToViewport(center[0], center[1]);
281
+ const worldSize = this.tileToViewportSize(tileX, tileY, z);
282
+ tileMesh.position.x = worldPosition[0];
283
+ tileMesh.position.z = worldPosition[1];
284
+ tileMesh.scaling.x = worldSize[0];
285
+ tileMesh.scaling.z = worldSize[1];
286
+ tileMesh.parent = this.layerRootNode;
287
+ this.updateTileTexture(tileX, tileY, z, tileMesh);
288
+ return tileMesh;
289
+ }
290
+ /**
291
+ * 获取调试画布
292
+ * @returns 调试画布元素
293
+ */
294
+ getTileCanvas(tileX, tileY, z) {
295
+ const canvas = document.createElement("canvas");
296
+ canvas.width = 256;
297
+ canvas.height = 256;
298
+ const ctx = canvas.getContext("2d");
299
+ if (ctx) {
300
+ ctx.fillStyle = "red";
301
+ ctx.font = "18px Arial";
302
+ ctx.textBaseline = "middle";
303
+ ctx.textAlign = "center";
304
+ ctx.fillText(`Tile: ${tileX}-${tileY}, ${z}`, canvas.width / 2, canvas.height / 2);
305
+ }
306
+ return canvas;
307
+ }
308
+ updateTileTexture(tileX, tileY, z, tileMesh) {
309
+ const canvas = document.createElement("canvas");
310
+ canvas.width = 256;
311
+ canvas.height = 256;
312
+ const ctx = canvas.getContext("2d");
313
+ if (ctx) {
314
+ ctx.fillStyle = "red";
315
+ ctx.font = "18px Arial";
316
+ ctx.textBaseline = "middle";
317
+ ctx.textAlign = "center";
318
+ ctx.fillText(`Tile: ${tileX}-${tileY}, ${z}`, canvas.width / 2, canvas.height / 2);
319
+ }
320
+ let material = tileMesh.material;
321
+ if (!material) {
322
+ material = new StandardMaterial(`tile-${tileX}-${tileY}-${z}`, this.mapViewer.scene);
323
+ material.specularColor = new Color3(0, 0, 0);
324
+ tileMesh.material = material;
325
+ }
326
+ this.tileLayers.forEach((tileLayer) => {
327
+ material.diffuseTexture = new Texture(tileLayer.getTileUrl(tileX, tileY, z), this.mapViewer.scene, false, true);
328
+ });
329
+ }
330
+ /**
331
+ * 根据当前视野范围和缩放级别计算需要渲染的瓦片列表
332
+ * @param zoom 缩放级别
333
+ * @returns 需要渲染的瓦片坐标数组 [[tileX, tileY, z], ...]
334
+ */
335
+ calculateVisibleTiles(zoom) {
336
+ const [bboxMinX, bboxMinY, bboxMaxX, bboxMaxY] = this.projectionBBox;
337
+ const [minTileX, maxTileY] = this.positionToTile(bboxMinX, bboxMinY, zoom);
338
+ const [maxTileX, minTileY] = this.positionToTile(bboxMaxX, bboxMaxY, zoom);
339
+ const visibleTiles = [];
340
+ for (let tileY = minTileY; tileY <= maxTileY; tileY++) {
341
+ for (let tileX = minTileX; tileX <= maxTileX; tileX++) {
342
+ const center = this.tileToCenter(tileX, tileY, zoom);
343
+ if (center[0] >= bboxMinX && center[0] <= bboxMaxX && center[1] >= bboxMinY && center[1] <= bboxMaxY) {
344
+ visibleTiles.push([tileX, tileY, zoom]);
345
+ }
346
+ }
347
+ }
348
+ return visibleTiles;
349
+ }
350
+ /**
351
+ * 更新瓦片渲染,只渲染当前视野内的瓦片
352
+ * @param zoom 缩放级别
353
+ */
354
+ updateTiles(zoom) {
355
+ this.currentZoom = zoom;
356
+ const visibleTiles = this.calculateVisibleTiles(zoom);
357
+ const shouldExistTiles = /* @__PURE__ */ new Set();
358
+ visibleTiles.forEach(([x, y, z]) => {
359
+ shouldExistTiles.add(`${x}-${y}-${z}`);
360
+ });
361
+ this.renderedTiles.forEach((mesh, key) => {
362
+ if (!shouldExistTiles.has(key)) {
363
+ mesh.dispose();
364
+ this.renderedTiles.delete(key);
365
+ }
366
+ });
367
+ visibleTiles.forEach(([tileX, tileY, z]) => {
368
+ const tileKey = `${tileX}-${tileY}-${z}`;
369
+ if (!this.renderedTiles.has(tileKey)) {
370
+ const tileMesh = this.getTileMesh(tileX, tileY, z);
371
+ this.renderedTiles.set(tileKey, tileMesh);
372
+ }
373
+ });
374
+ }
375
+ /**
376
+ * 启用自动更新模式,监听摄像机变化自动更新瓦片
377
+ * @param zoom 缩放级别
378
+ */
379
+ enableAutoUpdate(zoom = 0) {
380
+ this.autoUpdate = true;
381
+ this.currentZoom = zoom;
382
+ this.updateTiles(zoom);
383
+ const scene = this.mapViewer.scene;
384
+ if (scene.activeCamera) {
385
+ this.cameraObserver = scene.onAfterCameraRenderObservable.add(() => {
386
+ if (this.autoUpdate) {
387
+ this.updateTiles(this.currentZoom);
388
+ }
389
+ });
390
+ }
391
+ }
392
+ /**
393
+ * 禁用自动更新模式
394
+ */
395
+ disableAutoUpdate() {
396
+ this.autoUpdate = false;
397
+ if (this.cameraObserver) {
398
+ this.mapViewer.scene.onAfterCameraRenderObservable.remove(this.cameraObserver);
399
+ this.cameraObserver = null;
400
+ }
401
+ }
402
+ /**
403
+ * 设置缩放级别并更新瓦片
404
+ * @param zoom 缩放级别
405
+ */
406
+ setZoom(zoom) {
407
+ if (zoom !== this.currentZoom) {
408
+ this.currentZoom = zoom;
409
+ this.updateTiles(zoom);
410
+ }
411
+ }
412
+ /**
413
+ * 清除所有已渲染的瓦片
414
+ */
415
+ clearTiles() {
416
+ this.renderedTiles.forEach((mesh) => {
417
+ mesh.dispose();
418
+ });
419
+ this.renderedTiles.clear();
420
+ }
421
+ /**
422
+ * 释放资源
423
+ */
424
+ dispose() {
425
+ this.disableAutoUpdate();
426
+ this.clearTiles();
427
+ super.dispose();
428
+ }
429
+ }
430
+ const byteToHex = [];
431
+ for (let i = 0; i < 256; ++i) {
432
+ byteToHex.push((i + 256).toString(16).slice(1));
433
+ }
434
+ function unsafeStringify(arr, offset = 0) {
435
+ return (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + "-" + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + "-" + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + "-" + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + "-" + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase();
436
+ }
437
+ let getRandomValues;
438
+ const rnds8 = new Uint8Array(16);
439
+ function rng() {
440
+ if (!getRandomValues) {
441
+ if (typeof crypto === "undefined" || !crypto.getRandomValues) {
442
+ throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");
443
+ }
444
+ getRandomValues = crypto.getRandomValues.bind(crypto);
445
+ }
446
+ return getRandomValues(rnds8);
447
+ }
448
+ const _state = {};
449
+ function v1(options, buf, offset) {
450
+ let bytes;
451
+ {
452
+ const now = Date.now();
453
+ const rnds = rng();
454
+ updateV1State(_state, now, rnds);
455
+ bytes = v1Bytes(rnds, _state.msecs, _state.nsecs, _state.clockseq, _state.node, buf, offset);
456
+ }
457
+ return buf ?? unsafeStringify(bytes);
458
+ }
459
+ function updateV1State(state, now, rnds) {
460
+ state.msecs ?? (state.msecs = -Infinity);
461
+ state.nsecs ?? (state.nsecs = 0);
462
+ if (now === state.msecs) {
463
+ state.nsecs++;
464
+ if (state.nsecs >= 1e4) {
465
+ state.node = void 0;
466
+ state.nsecs = 0;
467
+ }
468
+ } else if (now > state.msecs) {
469
+ state.nsecs = 0;
470
+ } else if (now < state.msecs) {
471
+ state.node = void 0;
472
+ }
473
+ if (!state.node) {
474
+ state.node = rnds.slice(10, 16);
475
+ state.node[0] |= 1;
476
+ state.clockseq = (rnds[8] << 8 | rnds[9]) & 16383;
477
+ }
478
+ state.msecs = now;
479
+ return state;
480
+ }
481
+ function v1Bytes(rnds, msecs, nsecs, clockseq, node, buf, offset = 0) {
482
+ if (rnds.length < 16) {
483
+ throw new Error("Random bytes length must be >= 16");
484
+ }
485
+ if (!buf) {
486
+ buf = new Uint8Array(16);
487
+ offset = 0;
488
+ } else {
489
+ if (offset < 0 || offset + 16 > buf.length) {
490
+ throw new RangeError(`UUID byte range ${offset}:${offset + 15} is out of buffer bounds`);
491
+ }
492
+ }
493
+ msecs ?? (msecs = Date.now());
494
+ nsecs ?? (nsecs = 0);
495
+ clockseq ?? (clockseq = (rnds[8] << 8 | rnds[9]) & 16383);
496
+ node ?? (node = rnds.slice(10, 16));
497
+ msecs += 122192928e5;
498
+ const tl = ((msecs & 268435455) * 1e4 + nsecs) % 4294967296;
499
+ buf[offset++] = tl >>> 24 & 255;
500
+ buf[offset++] = tl >>> 16 & 255;
501
+ buf[offset++] = tl >>> 8 & 255;
502
+ buf[offset++] = tl & 255;
503
+ const tmh = msecs / 4294967296 * 1e4 & 268435455;
504
+ buf[offset++] = tmh >>> 8 & 255;
505
+ buf[offset++] = tmh & 255;
506
+ buf[offset++] = tmh >>> 24 & 15 | 16;
507
+ buf[offset++] = tmh >>> 16 & 255;
508
+ buf[offset++] = clockseq >>> 8 | 128;
509
+ buf[offset++] = clockseq & 255;
510
+ for (let n = 0; n < 6; ++n) {
511
+ buf[offset++] = node[n];
512
+ }
513
+ return buf;
514
+ }
515
+ var __defProp$2 = Object.defineProperty;
516
+ var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
517
+ var __publicField$2 = (obj, key, value) => __defNormalProp$2(obj, typeof key !== "symbol" ? key + "" : key, value);
518
+ class MapViewer {
519
+ /**
520
+ * 创建地图实例
521
+ * @param options 地图参数
522
+ */
523
+ constructor(options = {}, scene) {
524
+ __publicField$2(this, "id", v1());
525
+ __publicField$2(this, "name", "MapViewer");
526
+ __publicField$2(this, "rootNode");
527
+ __publicField$2(this, "projection", "EPSG:3857");
528
+ __publicField$2(this, "bbox", [-180, -90, 180, 90]);
529
+ __publicField$2(this, "size", [100, 100]);
530
+ __publicField$2(this, "tileLayerRenderer");
531
+ __publicField$2(this, "scene");
532
+ __publicField$2(this, "disposed", false);
533
+ __publicField$2(this, "zoomOffset", 1);
534
+ this.id = options.id || this.id;
535
+ this.name = options.name || this.name;
536
+ this.rootNode = new TransformNode(options.name || "MapViewerRootNode", scene);
537
+ this.rootNode.name = options.name || this.rootNode.name;
538
+ this.rootNode.metadata = { editable: false };
539
+ this.rootNode.doNotSerialize = true;
540
+ this.bbox = options.bbox || this.bbox;
541
+ this.projection = options.projection || this.projection;
542
+ this.zoomOffset = options.zoomOffset || this.zoomOffset;
543
+ this.setViewWidth(options.viewWidth || this.size[0]);
544
+ this.scene = scene;
545
+ this.tileLayerRenderer = new TileLayerRenderer(this);
546
+ this.tileLayerRenderer.updateTiles(this.getMinZoom() + this.zoomOffset);
547
+ }
548
+ setZoomOffset(zoomOffset) {
549
+ this.zoomOffset = Math.min(4, zoomOffset);
550
+ this.tileLayerRenderer.setZoom(this.getMinZoom() + zoomOffset);
551
+ }
552
+ setBBox(bbox) {
553
+ this.bbox = bbox;
554
+ this.setViewWidth(this.size[0]);
555
+ this.tileLayerRenderer.updateTiles(this.getMinZoom() + this.zoomOffset);
556
+ }
557
+ setViewWidth(viewWidth) {
558
+ const bbox = this.getProjectionBbox();
559
+ this.size = [viewWidth, (bbox[3] - bbox[1]) * viewWidth / (bbox[2] - bbox[0])];
560
+ if (this.tileLayerRenderer) {
561
+ this.tileLayerRenderer.updateTiles(this.getMinZoom() + this.zoomOffset);
562
+ }
563
+ }
564
+ getMinZoom() {
565
+ const bbox = this.getProjectionBbox();
566
+ const maxBBox = this.projection === "EPSG:3857" ? Projection.Max3857BBox : Projection.Max4326BBox;
567
+ const minZoom = Math.round(Math.log(Math.abs((maxBBox[2] - maxBBox[0]) / (bbox[3] - bbox[1]))) / Math.log(2));
568
+ return minZoom;
569
+ }
570
+ /**
571
+ * 设置地图投影坐标系
572
+ * @param projection 投影坐标系
573
+ */
574
+ setProjection(projection) {
575
+ this.projection = projection;
576
+ }
577
+ /**
578
+ * 获取地图投影坐标系
579
+ * @returns 投影坐标系
580
+ */
581
+ getProjectionBbox() {
582
+ const min = this.project([this.bbox[0], this.bbox[1]]);
583
+ const max = this.project([this.bbox[2], this.bbox[3]]);
584
+ return [min[0], min[1], max[0], max[1]];
585
+ }
586
+ /**
587
+ * 将wgs84坐标投影到地图坐标系
588
+ * @param coordinates 坐标
589
+ * @returns 投影后的坐标
590
+ */
591
+ project(coordinates) {
592
+ if (this.projection === "EPSG:3857") {
593
+ return Projection.EPSG4326To3857(coordinates);
594
+ }
595
+ return coordinates;
596
+ }
597
+ createGround() {
598
+ const ground = MeshBuilder.CreateGround("ground", { width: this.size[0], height: this.size[1] }, this.scene);
599
+ ground.parent = this.rootNode;
600
+ const groundMaterial = new GridMaterial("初始网格材质", this.scene);
601
+ groundMaterial.mainColor = new Color3(0, 0, 0);
602
+ groundMaterial.opacity = 0.8;
603
+ groundMaterial.lineColor = new Color3(0, 0, 0);
604
+ groundMaterial.backFaceCulling = false;
605
+ ground.material = groundMaterial;
606
+ }
607
+ dispose() {
608
+ this.disposed = true;
609
+ }
610
+ }
611
+ var __defProp$1 = Object.defineProperty;
612
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
613
+ var __publicField$1 = (obj, key, value) => __defNormalProp$1(obj, key + "", value);
7
614
  class CustomSystem {
8
- constructor(scene) {
615
+ constructor(scene, scriptInstanceList = [], environment) {
9
616
  this.scene = scene;
10
- this.load();
617
+ this.scriptInstanceList = scriptInstanceList;
618
+ __publicField$1(this, "mapViewers", []);
619
+ this.load(environment);
11
620
  }
12
- load() {
621
+ load(environment) {
13
622
  const transNodes = this.scene.transformNodes;
14
623
  for (let i = 0; i < transNodes.length; i++) {
15
624
  const transNode = transNodes[i];
16
625
  if (transNode.metadata) {
17
626
  const metaData = transNode.metadata;
18
627
  if (metaData.meshBuilderType === "assetModel" && metaData.assetModelBuilderOptions?.url) {
19
- CustomSystem.LoadAssetModel(transNode, metaData.assetModelBuilderOptions.url, this.scene);
628
+ CustomSystem.LoadAssetModel(transNode, metaData.assetModelBuilderOptions.url, this.scene).then(() => {
629
+ const findInstance = this.scriptInstanceList.find((instance) => instance.node === transNode);
630
+ if (findInstance && typeof findInstance.ready === "function") {
631
+ findInstance.ready();
632
+ }
633
+ });
634
+ } else if (metaData.meshBuilderType === "mapViewer" && metaData.mapViewerBuilderOptions) {
635
+ this.createMapViewer(transNode, metaData);
636
+ }
637
+ }
638
+ }
639
+ const cameras = this.scene.cameras;
640
+ for (let i = 0; i < cameras.length; i++) {
641
+ const camera = cameras[i];
642
+ if (camera.metadata && environment !== "editor") {
643
+ this.applyCameraBehavior(camera);
644
+ }
645
+ }
646
+ if (this.scene.environmentTexture) {
647
+ const url = this.scene.environmentTexture.url;
648
+ this.scene.environmentTexture = null;
649
+ setTimeout(() => {
650
+ try {
651
+ this.scene.environmentTexture = new HDRCubeTexture(url, this.scene, 256);
652
+ } catch (error) {
653
+ }
654
+ }, 1e3);
655
+ }
656
+ }
657
+ applyCameraBehavior(camera) {
658
+ const metaData = camera.metadata;
659
+ if (camera instanceof ArcRotateCamera && metaData) {
660
+ if (metaData.useAutoRotationBehavior && metaData.autoRotationBehavior) {
661
+ camera.useAutoRotationBehavior = true;
662
+ const autoRotationBehavior = camera.autoRotationBehavior;
663
+ if (autoRotationBehavior) {
664
+ autoRotationBehavior.zoomStopsAnimation = metaData.autoRotationBehavior.zoomStopsAnimation;
665
+ autoRotationBehavior.idleRotationSpeed = metaData.autoRotationBehavior.idleRotationSpeed;
666
+ autoRotationBehavior.idleRotationWaitTime = metaData.autoRotationBehavior.idleRotationWaitTime;
667
+ }
668
+ }
669
+ if (metaData.useFramingBehavior && metaData.framingBehavior) {
670
+ camera.useFramingBehavior = true;
671
+ const framingBehavior = camera.framingBehavior;
672
+ if (framingBehavior) {
673
+ framingBehavior.zoomStopsAnimation = metaData.framingBehavior.zoomStopsAnimation;
674
+ framingBehavior.defaultElevation = metaData.framingBehavior.defaultElevation;
675
+ framingBehavior.elevationReturnTime = metaData.framingBehavior.elevationReturnTime;
676
+ framingBehavior.elevationReturnWaitTime = metaData.framingBehavior.elevationReturnWaitTime;
677
+ framingBehavior.framingTime = metaData.framingBehavior.framingTime;
678
+ }
679
+ }
680
+ if (metaData.useBouncingBehavior && metaData.bouncingBehavior) {
681
+ camera.useBouncingBehavior = true;
682
+ if (camera.bouncingBehavior) {
683
+ camera.bouncingBehavior.autoTransitionRange = metaData.bouncingBehavior.autoTransitionRange || false;
684
+ camera.bouncingBehavior.lowerRadiusTransitionRange = metaData.bouncingBehavior.lowerRadiusTransitionRange || 2;
685
+ camera.bouncingBehavior.upperRadiusTransitionRange = metaData.bouncingBehavior.upperRadiusTransitionRange || -2;
20
686
  }
21
687
  }
22
688
  }
23
689
  }
690
+ /**
691
+ * 加载外部资源模型
692
+ * @param parentNode 父对象
693
+ * @param url 模型地址
694
+ * @param scene 场景
695
+ */
24
696
  static async LoadAssetModel(parentNode, url, scene) {
25
697
  const applyMetaData = (node) => {
26
698
  if (node instanceof Node && !node.parent) {
27
699
  node.parent = parentNode;
28
700
  }
29
- if (node instanceof Mesh && node.material) {
701
+ if (node instanceof AbstractMesh && node.material) {
30
702
  node.material.doNotSerialize = true;
31
703
  }
32
704
  node.doNotSerialize = true;
@@ -37,6 +709,32 @@ class CustomSystem {
37
709
  lights.forEach((node) => applyMetaData(node));
38
710
  skeletons.forEach((node) => applyMetaData(node));
39
711
  }
712
+ /**
713
+ * 创建地图查看器
714
+ * @param parentNode 父对象
715
+ * @param metaData 元数据
716
+ */
717
+ createMapViewer(parentNode, metaData) {
718
+ const mapViewer = new MapViewer({
719
+ id: metaData.mapViewerBuilderOptions?.id,
720
+ viewWidth: metaData.mapViewerBuilderOptions?.viewWidth,
721
+ bbox: [metaData.mapViewerBuilderOptions?.minX || -180, metaData.mapViewerBuilderOptions?.minY || -90, metaData.mapViewerBuilderOptions?.maxX || 180, metaData.mapViewerBuilderOptions?.maxY || 90]
722
+ }, this.scene);
723
+ parentNode.onDisposeObservable.addOnce(() => {
724
+ mapViewer.dispose();
725
+ this.mapViewers = this.mapViewers.filter((item) => item !== mapViewer);
726
+ });
727
+ mapViewer.rootNode.parent = parentNode;
728
+ this.mapViewers.push(mapViewer);
729
+ return mapViewer;
730
+ }
731
+ /**
732
+ * 根据ID获取地图查看器
733
+ * @param id 地图查看器ID
734
+ */
735
+ getMapViewerById(id) {
736
+ return this.mapViewers.find((item) => item.id === id);
737
+ }
40
738
  }
41
739
  var __defProp = Object.defineProperty;
42
740
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -48,24 +746,83 @@ class SceneLoader {
48
746
  * @param sceneData 场景数据
49
747
  * @param scriptsMap 脚本代码列表
50
748
  */
51
- constructor(container, sceneData, scriptsMap) {
749
+ constructor(container, sceneData, scriptsMap, option = {}) {
52
750
  __publicField(this, "container");
53
751
  __publicField(this, "canvas");
54
752
  __publicField(this, "engine");
55
753
  __publicField(this, "scene");
56
754
  __publicField(this, "sceneData", "");
57
- __publicField(this, "scritpsMap", {});
755
+ __publicField(this, "scriptsMap", {});
756
+ __publicField(this, "onLoadObservable", new Observable());
757
+ __publicField(this, "option", {});
58
758
  __publicField(this, "scriptInstanceList", []);
759
+ __publicField(this, "eventsSystem", {
760
+ click: [],
761
+ dblclick: [],
762
+ pointerdown: [],
763
+ pointerup: [],
764
+ pointermove: []
765
+ });
59
766
  this.container = container;
60
767
  this.canvas = document.createElement("canvas");
61
768
  this.canvas.className = "main-display-canvas";
62
769
  this.canvas.width = container.clientWidth;
63
770
  this.canvas.height = container.clientHeight;
64
771
  this.container.appendChild(this.canvas);
65
- this.engine = new Engine(this.canvas, true);
772
+ this.engine = new Engine(this.canvas, true, {
773
+ adaptToDeviceRatio: true,
774
+ antialias: true,
775
+ stencil: true,
776
+ preserveDrawingBuffer: true,
777
+ alpha: false
778
+ });
66
779
  this.scene = new Scene(this.engine);
780
+ this.option = {
781
+ showLoadingUI: true,
782
+ ...option
783
+ };
784
+ const resizeObserver = new ResizeObserver(() => {
785
+ this.canvas.width = container.clientWidth;
786
+ this.canvas.height = container.clientHeight;
787
+ this.engine.resize();
788
+ });
789
+ resizeObserver.observe(container);
67
790
  this.load(sceneData, scriptsMap);
68
791
  }
792
+ /**
793
+ * 初始化事件系统
794
+ */
795
+ initEvents() {
796
+ let lastClickTime = 0;
797
+ this.scene.onPointerObservable.add((pointerInfo) => {
798
+ switch (pointerInfo.type) {
799
+ case PointerEventTypes.POINTERDOWN:
800
+ const clickTime = Date.now();
801
+ if (clickTime - lastClickTime < 300) {
802
+ this.eventsSystem.dblclick.forEach((callback) => callback(pointerInfo));
803
+ } else {
804
+ lastClickTime = clickTime;
805
+ this.eventsSystem.click.forEach((callback) => callback(pointerInfo));
806
+ }
807
+ this.eventsSystem.pointerdown.forEach((callback) => callback(pointerInfo));
808
+ break;
809
+ case PointerEventTypes.POINTERUP:
810
+ this.eventsSystem.pointerup.forEach((callback) => callback(pointerInfo));
811
+ break;
812
+ case PointerEventTypes.POINTERMOVE:
813
+ this.eventsSystem.pointermove.forEach((callback) => callback(pointerInfo));
814
+ break;
815
+ }
816
+ });
817
+ }
818
+ // 绑定事件
819
+ on(eventName, callback) {
820
+ if (this.eventsSystem[eventName]) this.eventsSystem[eventName].push(callback);
821
+ }
822
+ // 解绑事件
823
+ off(eventName, callback) {
824
+ if (this.eventsSystem[eventName]) this.eventsSystem[eventName] = this.eventsSystem[eventName].filter((item) => item !== callback);
825
+ }
69
826
  /**
70
827
  * 加载场景
71
828
  * @param sceneData 场景数据数据
@@ -75,10 +832,11 @@ class SceneLoader {
75
832
  if (this.scene) {
76
833
  this.scene.dispose();
77
834
  }
78
- if (scriptsMap) this.scritpsMap = scriptsMap;
835
+ if (scriptsMap) this.scriptsMap = scriptsMap;
79
836
  this.scene = new Scene(this.engine);
80
837
  this.sceneData = sceneData;
81
838
  this.scriptInstanceList = [];
839
+ this.initEvents();
82
840
  this.scene.onBeforeRenderObservable.add(() => {
83
841
  if (this.scriptInstanceList) {
84
842
  const deltaTime = this.engine.getDeltaTime();
@@ -93,6 +851,7 @@ class SceneLoader {
93
851
  const havokModule = await HavokPhysics();
94
852
  this.scene.enablePhysics(new Vector3(0, -9.81, 0), new HavokPlugin(true, havokModule));
95
853
  await AppendSceneAsync("data:" + sceneData, this.scene);
854
+ if (!this.option.showLoadingUI) this.engine.hideLoadingUI();
96
855
  let camera;
97
856
  if (this.scene.cameras.length === 0) {
98
857
  camera = new FreeCamera("摄影机", new Vector3(50, 50, 50), this.scene, true);
@@ -100,9 +859,10 @@ class SceneLoader {
100
859
  camera = this.scene.activeCamera || this.scene.cameras[0];
101
860
  }
102
861
  camera.attachControl(this.canvas);
103
- new CustomSystem(this.scene);
104
862
  if (scriptsMap) this.initScripts(scriptsMap);
863
+ new CustomSystem(this.scene, this.scriptInstanceList, this.option.environment);
105
864
  this.render();
865
+ this.onLoadObservable.notifyObservers(this.scene);
106
866
  }
107
867
  /**
108
868
  * 初始化脚本
@@ -161,6 +921,169 @@ class SceneLoader {
161
921
  scene.render();
162
922
  });
163
923
  }
924
+ /**
925
+ * 根据名称获取节点
926
+ * @param name
927
+ * @returns
928
+ */
929
+ getNodeByName(name) {
930
+ return this.scene.getNodeByName(name);
931
+ }
932
+ getMeshByName(name) {
933
+ return this.scene.getMeshByName(name);
934
+ }
935
+ getLightByName(name) {
936
+ return this.scene.getLightByName(name);
937
+ }
938
+ getTransformNodeByName(name) {
939
+ return this.scene.getTransformNodeByName(name);
940
+ }
941
+ getCameraByName(name) {
942
+ return this.scene.getCameraByName(name);
943
+ }
944
+ /**
945
+ * 摄影机飞行到设置的位置锚点
946
+ * @param anchor 目标节点
947
+ * @param duration 飞行时间毫秒,ms
948
+ */
949
+ flyTo(anchor, duration = 2e3) {
950
+ if (this.scene.activeCamera) {
951
+ return SceneLoader.FlyTo(this.scene.activeCamera, anchor, duration);
952
+ }
953
+ return Promise.resolve();
954
+ }
955
+ /**
956
+ * 摄影机直接定位到设置的位置锚点
957
+ * @param anchor 目标节点
958
+ * @param camera 指定查看摄影机
959
+ */
960
+ viewTo(anchor) {
961
+ if (this.scene.activeCamera) {
962
+ SceneLoader.ViewTo(this.scene.activeCamera, anchor);
963
+ }
964
+ }
965
+ /**
966
+ * 根据名称摄影机飞行到设置的锚点
967
+ * @param name 摄影机锚点名称
968
+ * @param duration 飞行时间毫秒,ms
969
+ */
970
+ flyToAnchorByName(name, duration = 2e3) {
971
+ const camera = this.scene.activeCamera;
972
+ if (camera) {
973
+ const anchorList = camera.metadata?.cameraAnchorList || [];
974
+ const anchor = anchorList.find((item) => item.name === name);
975
+ if (anchor) {
976
+ return SceneLoader.FlyTo(camera, anchor, duration);
977
+ }
978
+ }
979
+ return Promise.resolve();
980
+ }
981
+ /**
982
+ * 根据名称摄影机飞行到设置的锚点
983
+ * @param name 摄影机锚点名称
984
+ * @param duration 飞行时间毫秒,ms
985
+ */
986
+ flyToAnchorByIndex(index, duration = 2e3) {
987
+ const camera = this.scene.activeCamera;
988
+ if (camera) {
989
+ const anchorList = camera.metadata?.cameraAnchorList || [];
990
+ const anchor = anchorList[index];
991
+ if (anchor) {
992
+ return SceneLoader.FlyTo(camera, anchor, duration);
993
+ }
994
+ }
995
+ return Promise.resolve();
996
+ }
997
+ /**
998
+ * 摄影机飞行到
999
+ * @param anchor 目标节点
1000
+ * @param duration 飞行时间毫秒,ms
1001
+ * @param camera 指定飞行摄影机
1002
+ */
1003
+ static FlyTo(camera, anchor, duration = 2e3) {
1004
+ return new Promise((resolve, reject) => {
1005
+ const easeFunction = new QuadraticEase();
1006
+ easeFunction.setEasingMode(EasingFunction.EASINGMODE_EASEOUT);
1007
+ const startTime = Date.now();
1008
+ const currentAnchor = {
1009
+ position: camera.position.asArray(),
1010
+ target: [0, 0, 0],
1011
+ radius: 0,
1012
+ alpha: 0,
1013
+ beta: 0
1014
+ };
1015
+ if (camera instanceof ArcRotateCamera) {
1016
+ currentAnchor.radius = camera.radius;
1017
+ currentAnchor.alpha = camera.alpha % (2 * Math.PI);
1018
+ currentAnchor.beta = camera.beta % Math.PI;
1019
+ currentAnchor.target = camera.target.asArray();
1020
+ if (Math.abs(currentAnchor.alpha - anchor.alpha) > Math.PI) {
1021
+ if (anchor.alpha > currentAnchor.alpha) {
1022
+ anchor.alpha -= 2 * Math.PI;
1023
+ } else {
1024
+ anchor.alpha += 2 * Math.PI;
1025
+ }
1026
+ }
1027
+ }
1028
+ if (camera instanceof TargetCamera) {
1029
+ currentAnchor.target = camera.target.asArray();
1030
+ }
1031
+ const getLinearValue = (start, end, val) => {
1032
+ return start + (end - start) * val;
1033
+ };
1034
+ const animate = () => {
1035
+ const elapsedTime = Date.now() - startTime;
1036
+ const val = easeFunction.ease(elapsedTime / duration);
1037
+ if (elapsedTime < duration) {
1038
+ requestAnimationFrame(animate);
1039
+ }
1040
+ if (camera instanceof ArcRotateCamera) {
1041
+ camera.radius = getLinearValue(currentAnchor.radius, anchor.radius, val);
1042
+ camera.alpha = getLinearValue(currentAnchor.alpha, anchor.alpha, val);
1043
+ camera.beta = getLinearValue(currentAnchor.beta, anchor.beta, val);
1044
+ const x = getLinearValue(currentAnchor.target[0], anchor.target[0], val);
1045
+ const y = getLinearValue(currentAnchor.target[1], anchor.target[1], val);
1046
+ const z = getLinearValue(currentAnchor.target[2], anchor.target[2], val);
1047
+ camera.target.x = x;
1048
+ camera.target.y = y;
1049
+ camera.target.z = z;
1050
+ } else if (camera instanceof TargetCamera) {
1051
+ const px = getLinearValue(currentAnchor.position[0], anchor.position[0], val);
1052
+ const py = getLinearValue(currentAnchor.position[1], anchor.position[1], val);
1053
+ const pz = getLinearValue(currentAnchor.position[2], anchor.position[2], val);
1054
+ camera.position = new Vector3(px, py, pz);
1055
+ const x = getLinearValue(currentAnchor.target[0], anchor.target[0], val);
1056
+ const y = getLinearValue(currentAnchor.target[1], anchor.target[1], val);
1057
+ const z = getLinearValue(currentAnchor.target[2], anchor.target[2], val);
1058
+ camera.target.x = x;
1059
+ camera.target.y = y;
1060
+ camera.target.z = z;
1061
+ }
1062
+ if (elapsedTime >= duration) {
1063
+ resolve();
1064
+ }
1065
+ };
1066
+ animate();
1067
+ });
1068
+ }
1069
+ /**
1070
+ * 摄影机定位到
1071
+ * @param anchor 目标节点
1072
+ * @param camera 指定查看摄影机
1073
+ */
1074
+ static ViewTo(camera, anchor) {
1075
+ let activeCamera = camera;
1076
+ if (activeCamera) {
1077
+ activeCamera.position = new Vector3(anchor.position[0], anchor.position[1], anchor.position[2]);
1078
+ if (activeCamera instanceof ArcRotateCamera) {
1079
+ activeCamera.radius = anchor.radius;
1080
+ activeCamera.alpha = anchor.alpha;
1081
+ activeCamera.beta = anchor.beta;
1082
+ } else if (activeCamera instanceof TargetCamera) {
1083
+ activeCamera.setTarget(new Vector3(anchor.target[0], anchor.target[1], anchor.target[2]));
1084
+ }
1085
+ }
1086
+ }
164
1087
  /**
165
1088
  * 重置canvas变形后的系统尺寸
166
1089
  */
@@ -177,8 +1100,8 @@ class SceneLoader {
177
1100
  static LoadCustomSystem() {
178
1101
  }
179
1102
  }
180
- function loadScene(container, sceneData, scriptsMap = {}) {
181
- const sceneLoader = new SceneLoader(container, sceneData, scriptsMap);
1103
+ function loadScene(container, sceneData, scriptsMap = {}, option) {
1104
+ const sceneLoader = new SceneLoader(container, sceneData, scriptsMap, option);
182
1105
  return sceneLoader;
183
1106
  }
184
1107
  export {