@kimap/indoor-positioning-sdk-vue2 5.8.2 → 5.8.4

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kimap/indoor-positioning-sdk-vue2",
3
- "version": "5.8.2",
3
+ "version": "5.8.4",
4
4
  "description": "Vue2自包含室内定位SDK - 完全兼容Webpack3+Babel6 | Vue2 Self-Contained Indoor Positioning SDK",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -43,6 +43,7 @@ function KimapSDK(config) {
43
43
  this.floorToolsConfig = config.floorTools || { enabled: false };
44
44
  this.floorToolsElement = null;
45
45
  this.currentFloorIndex = 1; // 1=第一个楼层, 0=ALL
46
+ this._currentShowingFloorIndex = 0; // 当前显示的楼层索引(用于判断动画方向)
46
47
  }
47
48
 
48
49
  /**
@@ -143,23 +144,31 @@ KimapSDK.prototype.handleClick = function(event) {
143
144
  */
144
145
  KimapSDK.prototype.startRenderLoop = function() {
145
146
  var self = this;
146
-
147
+ var lastTime = Date.now();
148
+
147
149
  function animate() {
148
150
  self.animationFrameId = requestAnimationFrame(animate);
149
-
151
+
152
+ var now = Date.now();
153
+ var deltaMs = now - lastTime;
154
+ lastTime = now;
155
+
156
+ // 驱动楼层切换动画 & 相机俯仰动画
157
+ self.core.tickAnimations(deltaMs);
158
+
150
159
  if (self.core.controls) {
151
160
  self.core.controls.update();
152
161
  }
153
-
162
+
154
163
  if (self.trackingModule) {
155
164
  self.trackingModule.update();
156
165
  }
157
-
166
+
158
167
  self.updateAllDOMPositions();
159
-
168
+
160
169
  self.core.renderer.render(self.core.scene, self.core.camera);
161
170
  }
162
-
171
+
163
172
  animate();
164
173
  };
165
174
 
@@ -606,18 +615,70 @@ KimapSDK.prototype.changeFloor = function(floorIdOrIndex) {
606
615
  KimapSDK.prototype.showSingleFloor = function(floorIndex) {
607
616
  if (!this.floorGroups || this.floorGroups.length === 0) return;
608
617
  var self = this;
618
+
619
+ var ANIM_DURATION = 400; // ms
620
+ var startTime = Date.now();
621
+ var currentFloorIndex = this._currentShowingFloorIndex !== undefined
622
+ ? this._currentShowingFloorIndex : 0;
623
+
624
+ // 判断方向:目标层是从上方滑下(低→高)还是从下方滑上(高→低)
625
+ // 低楼层 → 高楼层(1→2):目标层从上方来
626
+ // 高楼层 → 低楼层(2→1):目标层从下方来
627
+ var targetFromAbove = floorIndex > currentFloorIndex;
628
+
629
+ // 计算目标 Y
630
+ function targetY(index) {
631
+ if (index === floorIndex) return 0;
632
+ var origY = self.core.floorOriginalY[index] || 0;
633
+ return -origY - 1;
634
+ }
635
+
636
+ // 滑入起始偏移:目标层从 ±(楼层高度+内容高度) 处开始
637
+ var slideOffset = 8; // 一个楼层的视觉高度约 8 单位
638
+ function slideStartY(index) {
639
+ return targetFromAbove ? slideOffset : -slideOffset;
640
+ }
641
+
642
+ var steps = [];
609
643
  this.floorGroups.forEach(function(group, index) {
610
644
  if (index === floorIndex) {
611
- // 单层模式:将该楼层移动到贴地位置(y = 0
645
+ // 目标层:先设 visible,再从滑入起始位开始动画到 y=0
612
646
  group.visible = true;
613
- group.position.y = 0;
647
+ group.position.y = slideStartY(index);
648
+ steps.push({ group: group, fromY: slideStartY(index), toY: 0, toVisible: true });
614
649
  } else {
615
- // 隐藏其他楼层,同时移到下方避免干扰
616
- group.visible = false;
617
- var originalY = self.core.floorOriginalY[index] || 0;
618
- group.position.y = -originalY - 1; // 移到地面以下
650
+ // 离场层:动画到隐藏位置后设 visible=false
651
+ var fromY = group.position.y;
652
+ var toY = targetY(index);
653
+ steps.push({ group: group, fromY: fromY, toY: toY, toVisible: false });
619
654
  }
620
655
  });
656
+
657
+ // 合并/覆盖已有动画:先停止当前帧再以新起止值启动
658
+ if (self.core.floorAnim && self.core.floorAnim.running) {
659
+ var cur = self.core.floorAnim;
660
+ var t = Math.min((Date.now() - cur.startTime) / cur.duration, 1);
661
+ var et = 1 - Math.pow(1 - t, 3); // easeOutCubic reverse
662
+ // 把每个 group 瞬移到当前动画帧的位置
663
+ for (var i = 0; i < cur.steps.length; i++) {
664
+ var cs = cur.steps[i];
665
+ cs.group.position.y = cs.fromY + (cs.toY - cs.fromY) * et;
666
+ }
667
+ }
668
+
669
+ self.core.floorAnim = {
670
+ running: true,
671
+ startTime: startTime,
672
+ duration: ANIM_DURATION,
673
+ steps: steps
674
+ };
675
+
676
+ this._currentShowingFloorIndex = floorIndex;
677
+ // 相机对准当前楼层(带相机俯仰动画)
678
+ if (self.core.cameraPitchState === 1) {
679
+ self.core.animateCameraToFloorView(600);
680
+ }
681
+ self.core.adjustCameraToFloor(floorIndex);
621
682
  };
622
683
 
623
684
  /**
@@ -627,12 +688,21 @@ KimapSDK.prototype.showSingleFloor = function(floorIndex) {
627
688
  KimapSDK.prototype.showAllFloors = function() {
628
689
  if (!this.floorGroups || this.floorGroups.length === 0) return;
629
690
  var self = this;
691
+
692
+ // 楼层组瞬间恢复到 ALL 位置(不需要动画,因为相机视角切换是主角)
630
693
  this.floorGroups.forEach(function(group, index) {
631
694
  group.visible = true;
632
- // 恢复原始世界 Y 偏移(含间隙)
633
695
  var originalY = self.core.floorOriginalY[index] || 0;
634
696
  group.position.y = originalY;
635
697
  });
698
+
699
+ // 先让相机以所有楼层合并包围盒调整一次(决定 toPos/toTarget)
700
+ self.core._adjustCameraToAllFloors();
701
+
702
+ // 再启动相机俯仰动画(从当前单楼层视角 → -60° 外景视角)
703
+ self.core.animateCameraToAllView(800);
704
+
705
+ this._currentShowingFloorIndex = -1; // ALL 状态
636
706
  };
637
707
 
638
708
  /**
@@ -1505,13 +1575,13 @@ KimapSDK.prototype._renderFloorSelector = function() {
1505
1575
  ].join(';');
1506
1576
 
1507
1577
  // ALL 按钮
1508
- var allBtn = this._createFloorButton('ALL', 0, this.currentFloorIndex === 0);
1578
+ var allBtn = this._createFloorButton('ALL', 0);
1509
1579
  selector.appendChild(allBtn);
1510
1580
 
1511
1581
  // 各楼层按钮
1512
1582
  var self2 = this;
1513
1583
  floorNames.forEach(function(name, index) {
1514
- var btn = self2._createFloorButton(name, index + 1, self2.currentFloorIndex === index + 1);
1584
+ var btn = self2._createFloorButton(name, index + 1);
1515
1585
  selector.appendChild(btn);
1516
1586
  });
1517
1587
 
@@ -1523,7 +1593,7 @@ KimapSDK.prototype._renderFloorSelector = function() {
1523
1593
  * 创建楼层按钮
1524
1594
  * @private
1525
1595
  */
1526
- KimapSDK.prototype._createFloorButton = function(name, index, isActive) {
1596
+ KimapSDK.prototype._createFloorButton = function(name, index) {
1527
1597
  var self = this;
1528
1598
  var btn = document.createElement('button');
1529
1599
  btn.textContent = name;
@@ -1540,27 +1610,32 @@ KimapSDK.prototype._createFloorButton = function(name, index, isActive) {
1540
1610
  'min-width: 50px'
1541
1611
  ].join(';');
1542
1612
 
1543
- if (isActive) {
1544
- btn.style.backgroundColor = '#1890ff';
1545
- btn.style.color = '#fff';
1546
- } else {
1547
- btn.style.backgroundColor = 'rgba(255, 255, 255, 0.9)';
1548
- btn.style.color = '#333';
1549
- btn.style.boxShadow = '0 1px 4px rgba(0,0,0,0.1)';
1613
+ function applyActiveStyle(active) {
1614
+ if (active) {
1615
+ btn.style.backgroundColor = '#1890ff';
1616
+ btn.style.color = '#fff';
1617
+ btn.style.boxShadow = 'none';
1618
+ } else {
1619
+ btn.style.backgroundColor = 'rgba(255, 255, 255, 0.9)';
1620
+ btn.style.color = '#333';
1621
+ btn.style.boxShadow = '0 1px 4px rgba(0,0,0,0.1)';
1622
+ }
1550
1623
  }
1551
1624
 
1625
+ applyActiveStyle(self.currentFloorIndex === index);
1626
+
1552
1627
  btn.addEventListener('click', function() {
1553
1628
  self._onFloorButtonClick(index);
1554
1629
  });
1555
1630
 
1556
1631
  btn.addEventListener('mouseenter', function() {
1557
- if (!isActive) {
1632
+ if (self.currentFloorIndex !== index) {
1558
1633
  btn.style.backgroundColor = '#e6f7ff';
1559
1634
  }
1560
1635
  });
1561
1636
 
1562
1637
  btn.addEventListener('mouseleave', function() {
1563
- if (!isActive) {
1638
+ if (self.currentFloorIndex !== index) {
1564
1639
  btn.style.backgroundColor = 'rgba(255, 255, 255, 0.9)';
1565
1640
  }
1566
1641
  });
@@ -42,6 +42,7 @@ function SceneCore(config) {
42
42
  this.renderer = null;
43
43
  this.controls = null;
44
44
  this.mapModel = null;
45
+ this.lookAtTarget = null; // 当前相机注视点(ALL 退场恢复用)
45
46
 
46
47
  // 需要先加载 THREE 才能使用 THREE.Vector3
47
48
  var mapWidth = config.maxX || 100;
@@ -67,6 +68,13 @@ function SceneCore(config) {
67
68
  this.floorHeight = 3; // 米
68
69
  this.isMultiFloor = Array.isArray(config.objUrl);
69
70
  this.floorOriginalY = []; // 每个楼层的原始世界Y偏移(含间隙)
71
+ // 楼层切换动画状态
72
+ this.floorAnim = null; // { running: bool, startTime: ms, duration: ms, queue: [] }
73
+ // 相机俯仰动画(ALL 模式)
74
+ this.cameraPitchAnim = null; // { running: bool, startTime: ms, duration: ms }
75
+ this.cameraPitchState = 0; // 0=正常视角, 1=ALL外景俯视
76
+ this.cameraPrePitchPos = null; // 俯仰动画前的相机位置
77
+ this.cameraPrePitchTarget = null; // 俯仰动画前的 controls.target
70
78
  }
71
79
 
72
80
  /**
@@ -282,8 +290,9 @@ SceneCore.prototype._loadMultiFloorMaps = function(OBJLoader, MTLLoader, objUrls
282
290
  return self._loadSingleMapWithFloorIndex(OBJLoader, MTLLoader, url, floorIndex++);
283
291
  });
284
292
  }, Promise.resolve()).then(function() {
285
- if (self.floorGroups.length > 1) {
286
- self._adjustCameraToAllFloors();
293
+ // 多楼层:相机默认以第一个楼层为准(之后切换 ALL 时再重新调整)
294
+ if (self.floorGroups.length > 0) {
295
+ self.adjustCameraToFloor(0);
287
296
  }
288
297
  });
289
298
  };
@@ -421,7 +430,8 @@ SceneCore.prototype._processLoadedModelToGroup = function(object, materials, col
421
430
  var box = new THREE.Box3().setFromObject(object);
422
431
  var boxHeight = box.max.y - box.min.y;
423
432
 
424
- // 逐层累积高度:计算该楼层在 ALL 模式下的世界 Y 偏移
433
+ // 逐层累积高度:ALL 模式时,每层 = 前几层高度 + floorHeight 间隙
434
+ // 这样 ALL 有间隙,单层模式时把 group.position.y = -floorY 就贴地了
425
435
  var floorY = 0;
426
436
  for (var i = 0; i < floorIndex; i++) {
427
437
  var prevGroup = self.floorGroups[i];
@@ -431,14 +441,17 @@ SceneCore.prototype._processLoadedModelToGroup = function(object, materials, col
431
441
  }
432
442
  }
433
443
 
444
+ // 加固定间隙高度(除第一个楼层外)
445
+ var totalFloorY = floorY + floorIndex * self.floorHeight;
446
+
434
447
  // 所有楼层的 object 底部(box.min.y)对齐到本地 Y=0,统一基准
435
448
  object.position.set(-box.min.x, -box.min.y, -box.min.z);
436
449
 
437
- // ALL 模式时 floorGroup.position.y 持有累积偏移(含间隙)
438
- floorGroup.position.y = floorY;
450
+ // ALL 模式时 floorGroup.position.y 持有含间隙的累积偏移
451
+ floorGroup.position.y = totalFloorY;
439
452
 
440
- // 记录每个楼层的原始世界 Y 偏移(单层模式时用于将选中层拽回 Y=0)
441
- self.floorOriginalY[floorIndex] = floorY;
453
+ // 记录含间隙的总世界 Y 偏移(单层模式 showSingleFloor 用 group.y = -originalY 拽回 Y=0)
454
+ self.floorOriginalY[floorIndex] = totalFloorY;
442
455
 
443
456
  // 为该楼层创建独立的文字组
444
457
  var textGroup = new THREE.Group();
@@ -495,6 +508,48 @@ SceneCore.prototype._adjustCameraToAllFloors = function() {
495
508
  }
496
509
  };
497
510
 
511
+ /**
512
+ * 相机对准指定楼层(多楼层切换/ALL 时分别调用)
513
+ * @param {number} floorIndex - 楼层索引
514
+ * @public
515
+ */
516
+ SceneCore.prototype.adjustCameraToFloor = function(floorIndex) {
517
+ try {
518
+ var floorGroup = this.floorGroups[floorIndex];
519
+ if (!floorGroup) return;
520
+
521
+ var meshes = [];
522
+ floorGroup.traverse(function(child) {
523
+ if (child.isMesh) meshes.push(child);
524
+ });
525
+ if (meshes.length === 0) return;
526
+
527
+ var box = new THREE.Box3();
528
+ meshes.forEach(function(mesh) { box.expandByObject(mesh); });
529
+
530
+ var center = new THREE.Vector3();
531
+ var size = new THREE.Vector3();
532
+ box.getCenter(center);
533
+ box.getSize(size);
534
+ var maxSize = Math.max(size.x, size.z);
535
+ var distance = maxSize * 2;
536
+
537
+ this.camera.position.set(center.x, center.y + distance * 1.5, center.z + distance);
538
+ var lookAtTgt = new THREE.Vector3(center.x, center.y, center.z);
539
+ this.camera.lookAt(lookAtTgt);
540
+ if (this.controls) {
541
+ this.controls.target.copy(lookAtTgt);
542
+ this.controls.update();
543
+ }
544
+ // 记录当前 lookAt 目标(ALL 退场恢复用)
545
+ this.camera.lookAtTarget = lookAtTgt;
546
+ this.coordinateSystem.maxX = size.x;
547
+ this.coordinateSystem.maxY = size.z;
548
+ } catch (e) {
549
+ console.warn('调整相机到楼层 ' + floorIndex + ' 失败:', e);
550
+ }
551
+ };
552
+
498
553
  /**
499
554
  * 加载 Kimap 加密文件(内部方法)
500
555
  * @private
@@ -1158,4 +1213,194 @@ SceneCore.prototype.destroy = function() {
1158
1213
  }
1159
1214
  };
1160
1215
 
1216
+ // =============================================================================
1217
+ // 动画工具:缓动函数
1218
+ // =============================================================================
1219
+ function easeOutCubic(t) { return 1 - Math.pow(1 - t, 3); }
1220
+ function easeInOutCubic(t) { return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2; }
1221
+
1222
+ /**
1223
+ * 每帧调用:驱动楼层切换动画 & 相机俯仰动画
1224
+ * 由 KimapSDK.renderLoop 内部调用
1225
+ * @param {number} deltaMs - 距上一帧的毫秒数
1226
+ */
1227
+ SceneCore.prototype.tickAnimations = function(deltaMs) {
1228
+ // ---------- 楼层切换动画 ----------
1229
+ if (this.floorAnim && this.floorAnim.running) {
1230
+ var elapsed = Date.now() - this.floorAnim.startTime;
1231
+ var t = Math.min(elapsed / this.floorAnim.duration, 1);
1232
+ var et = easeOutCubic(t);
1233
+
1234
+ var steps = this.floorAnim.steps;
1235
+ for (var i = 0; i < steps.length; i++) {
1236
+ var step = steps[i];
1237
+ var fromY = step.fromY;
1238
+ var toY = step.toY;
1239
+ step.group.position.y = fromY + (toY - fromY) * et;
1240
+ }
1241
+
1242
+ if (t >= 1) {
1243
+ // 动画结束:立即到达目标,更新最终状态
1244
+ for (var j = 0; j < steps.length; j++) {
1245
+ var s = steps[j];
1246
+ s.group.position.y = s.toY;
1247
+ if (s.toVisible === false) {
1248
+ s.group.visible = false;
1249
+ }
1250
+ }
1251
+ this.floorAnim = null;
1252
+ }
1253
+ }
1254
+
1255
+ // ---------- 相机俯仰动画(ALL 外景) ----------
1256
+ if (this.cameraPitchAnim && this.cameraPitchAnim.running) {
1257
+ var elapsed2 = Date.now() - this.cameraPitchAnim.startTime;
1258
+ var t2 = Math.min(elapsed2 / this.cameraPitchAnim.duration, 1);
1259
+ var et2 = easeInOutCubic(t2);
1260
+
1261
+ var fromPos = this.cameraPitchAnim.fromPos;
1262
+ var toPos = this.cameraPitchAnim.toPos;
1263
+ var fromTarget = this.cameraPitchAnim.fromTarget;
1264
+ var toTarget = this.cameraPitchAnim.toTarget;
1265
+
1266
+ this.camera.position.lerpVectors(fromPos, toPos, et2);
1267
+ this.camera.lookAt(
1268
+ fromTarget.x + (toTarget.x - fromTarget.x) * et2,
1269
+ fromTarget.y + (toTarget.y - fromTarget.y) * et2,
1270
+ fromTarget.z + (toTarget.z - fromTarget.z) * et2
1271
+ );
1272
+ if (this.controls) {
1273
+ this.controls.target.copy(this.camera);
1274
+ this.controls.target.y = fromTarget.y + (toTarget.y - fromTarget.y) * et2;
1275
+ this.controls.update();
1276
+ }
1277
+
1278
+ if (t2 >= 1) {
1279
+ this.camera.position.copy(toPos);
1280
+ this.camera.lookAt(toTarget);
1281
+ if (this.controls) {
1282
+ this.controls.target.copy(toTarget);
1283
+ this.controls.update();
1284
+ }
1285
+ this.cameraPitchAnim = null;
1286
+ }
1287
+ }
1288
+ };
1289
+
1290
+ /**
1291
+ * 计算整栋建筑的包围盒中心(ALL 相机动画用)
1292
+ * @returns {{center: THREE.Vector3, maxSize: number}}
1293
+ */
1294
+ SceneCore.prototype._getBuildingBounds = function() {
1295
+ var allMeshes = [];
1296
+ this.floorGroups.forEach(function(group) {
1297
+ group.traverse(function(child) {
1298
+ if (child.isMesh) allMeshes.push(child);
1299
+ });
1300
+ });
1301
+ if (allMeshes.length === 0) return null;
1302
+
1303
+ var box = new THREE.Box3();
1304
+ allMeshes.forEach(function(mesh) { box.expandByObject(mesh); });
1305
+ var center = new THREE.Vector3();
1306
+ var size = new THREE.Vector3();
1307
+ box.getCenter(center);
1308
+ box.getSize(size);
1309
+ return { center: center, maxSize: Math.max(size.x, size.z) };
1310
+ };
1311
+
1312
+ /**
1313
+ * ALL 入口:相机降至低俯角(-60°),模拟建筑外观视角
1314
+ * @param {number} duration - 动画时长(ms)
1315
+ */
1316
+ SceneCore.prototype.animateCameraToAllView = function(duration) {
1317
+ duration = duration || 800;
1318
+ var self = this;
1319
+
1320
+ // 已有动画在跑 → 停止,先瞬移到当前帧再启动新动画
1321
+ if (this.cameraPitchAnim && this.cameraPitchAnim.running) {
1322
+ var cur = this.cameraPitchAnim;
1323
+ var tCur = Math.min((Date.now() - cur.startTime) / cur.duration, 1);
1324
+ var etCur = easeInOutCubic(tCur);
1325
+ this.camera.position.lerpVectors(cur.fromPos, cur.toPos, etCur);
1326
+ this.camera.lookAt(
1327
+ cur.fromTarget.x + (cur.toTarget.x - cur.fromTarget.x) * etCur,
1328
+ cur.fromTarget.y + (cur.toTarget.y - cur.fromTarget.y) * etCur,
1329
+ cur.fromTarget.z + (cur.toTarget.z - cur.fromTarget.z) * etCur
1330
+ );
1331
+ if (this.controls) this.controls.update();
1332
+ this.cameraPitchAnim = null;
1333
+ }
1334
+
1335
+ var bounds = this._getBuildingBounds();
1336
+ if (!bounds) return;
1337
+
1338
+ var center = bounds.center;
1339
+ var maxSize = bounds.maxSize;
1340
+
1341
+ // 保存退场时需恢复的位置(单楼层相机视角)
1342
+ this.cameraPrePitchPos = this.camera.position.clone();
1343
+ this.cameraPrePitchTarget = this.controls ? this.controls.target.clone() : center.clone();
1344
+
1345
+ // 低俯角 -60°:camera.y - center.y = distance × sin(-60°) = -distance × 0.866
1346
+ // camera.z - center.z = distance × cos(-60°) = distance × 0.5
1347
+ var dist = maxSize * 2.5;
1348
+ var fromPos = this.camera.position.clone();
1349
+ var fromTarget = this.controls ? this.controls.target.clone() : center.clone();
1350
+ var toPos = new THREE.Vector3(center.x, center.y - dist * 0.866, center.z + dist * 0.5);
1351
+ var toTarget = new THREE.Vector3(center.x, center.y, center.z);
1352
+
1353
+ this.cameraPitchAnim = {
1354
+ running: true,
1355
+ startTime: Date.now(),
1356
+ duration: duration,
1357
+ fromPos: fromPos,
1358
+ toPos: toPos,
1359
+ fromTarget: fromTarget,
1360
+ toTarget: toTarget
1361
+ };
1362
+ this.cameraPitchState = 1;
1363
+ };
1364
+
1365
+ /**
1366
+ * ALL 出口:相机从外景视角恢复到单楼层视角
1367
+ * @param {number} duration - 动画时长(ms)
1368
+ */
1369
+ SceneCore.prototype.animateCameraToFloorView = function(duration) {
1370
+ duration = duration || 800;
1371
+ var self = this;
1372
+
1373
+ // 先停止当前相机动画并瞬移到当前帧
1374
+ if (this.cameraPitchAnim && this.cameraPitchAnim.running) {
1375
+ var cur = this.cameraPitchAnim;
1376
+ var tCur = Math.min((Date.now() - cur.startTime) / cur.duration, 1);
1377
+ var etCur = easeInOutCubic(tCur);
1378
+ this.camera.position.lerpVectors(cur.fromPos, cur.toPos, etCur);
1379
+ this.camera.lookAt(
1380
+ cur.fromTarget.x + (cur.toTarget.x - cur.fromTarget.x) * etCur,
1381
+ cur.fromTarget.y + (cur.toTarget.y - cur.fromTarget.y) * etCur,
1382
+ cur.fromTarget.z + (cur.toTarget.z - cur.fromTarget.z) * etCur
1383
+ );
1384
+ if (this.controls) this.controls.update();
1385
+ this.cameraPitchAnim = null;
1386
+ }
1387
+
1388
+ // 退场恢复点
1389
+ var toPos = this.cameraPrePitchPos || this.camera.position.clone();
1390
+ var toTarget = this.cameraPrePitchTarget || this.camera.position.clone();
1391
+
1392
+ this.cameraPitchAnim = {
1393
+ running: true,
1394
+ startTime: Date.now(),
1395
+ duration: duration,
1396
+ fromPos: this.camera.position.clone(),
1397
+ toPos: toPos,
1398
+ fromTarget: this.camera.lookAtTarget ? this.camera.lookAtTarget.clone() : toTarget.clone(),
1399
+ toTarget: toTarget
1400
+ };
1401
+ this.cameraPitchState = 0;
1402
+ this.cameraPrePitchPos = null;
1403
+ this.cameraPrePitchTarget = null;
1404
+ };
1405
+
1161
1406
  module.exports = SceneCore;