@kimap/indoor-positioning-sdk-vue2 5.8.7 → 5.9.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.
- package/package.json +1 -1
- package/src/core/KimapSDK.js +19 -90
- package/src/core/SceneCore.js +56 -22
package/package.json
CHANGED
package/src/core/KimapSDK.js
CHANGED
|
@@ -10,10 +10,6 @@ var SceneCore = require('./SceneCore.js');
|
|
|
10
10
|
// THREE.js 将在运行时加载
|
|
11
11
|
var THREE = null;
|
|
12
12
|
var loadThree = loaders.loadThree;
|
|
13
|
-
|
|
14
|
-
function easeInOutCubic(t) {
|
|
15
|
-
return t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2;
|
|
16
|
-
}
|
|
17
13
|
var loadOBJLoader = loaders.loadOBJLoader;
|
|
18
14
|
var loadFBXLoader = loaders.loadFBXLoader;
|
|
19
15
|
var loadGLTFLoader = loaders.loadGLTFLoader;
|
|
@@ -88,9 +84,10 @@ KimapSDK.prototype.init = function() {
|
|
|
88
84
|
self.startRenderLoop();
|
|
89
85
|
self._extractWallsFromModel();
|
|
90
86
|
|
|
91
|
-
//
|
|
87
|
+
// 多楼层默认显示第一个楼层,并设 -60° 俯角相机
|
|
92
88
|
if (self.isMultiFloor && self.floorGroups && self.floorGroups.length > 0) {
|
|
93
89
|
self.showSingleFloor(0);
|
|
90
|
+
self.core.adjustCameraToSingleFloorView(0);
|
|
94
91
|
}
|
|
95
92
|
|
|
96
93
|
// 渲染内置楼层选择器 UI
|
|
@@ -628,66 +625,38 @@ KimapSDK.prototype.showSingleFloor = function(floorIndex) {
|
|
|
628
625
|
// 判断方向:目标层是从上方滑下(低→高)还是从下方滑上(高→低)
|
|
629
626
|
var targetFromAbove = floorIndex > currentFloorIndex;
|
|
630
627
|
|
|
631
|
-
//
|
|
628
|
+
// 滑入起始偏移(减小幅度,约原值的50%)
|
|
632
629
|
var slideOffset = 4;
|
|
633
630
|
|
|
634
631
|
var steps = [];
|
|
635
|
-
var fromAll = (currentFloorIndex === -1); // 是否从 ALL 模式切来
|
|
636
|
-
|
|
637
632
|
this.floorGroups.forEach(function(group, idx) {
|
|
638
633
|
if (idx === floorIndex) {
|
|
639
|
-
//
|
|
640
|
-
if (fromAll) {
|
|
641
|
-
var origY = self.core.floorOriginalY[idx] || 0;
|
|
642
|
-
group.position.y = origY;
|
|
643
|
-
} else {
|
|
644
|
-
group.position.y = targetFromAbove ? slideOffset : -slideOffset;
|
|
645
|
-
}
|
|
634
|
+
// 目标层:从偏移位滑入到 y=0
|
|
646
635
|
group.visible = true;
|
|
636
|
+
group.position.y = targetFromAbove ? slideOffset : -slideOffset;
|
|
647
637
|
steps.push({
|
|
648
638
|
group: group,
|
|
649
|
-
fromY:
|
|
639
|
+
fromY: targetFromAbove ? slideOffset : -slideOffset,
|
|
650
640
|
toY: 0,
|
|
651
641
|
toVisible: true
|
|
652
642
|
});
|
|
653
643
|
} else {
|
|
654
|
-
//
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
var et = 1 - Math.pow(1 - t, 3);
|
|
659
|
-
for (var i = 0; i < cur.steps.length; i++) {
|
|
660
|
-
var cs = cur.steps[i];
|
|
661
|
-
if (cs.group === group) {
|
|
662
|
-
group.position.y = cs.fromY + (cs.toY - cs.fromY) * et;
|
|
663
|
-
break;
|
|
664
|
-
}
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
var origY2 = self.core.floorOriginalY[idx] || 0;
|
|
668
|
-
// 从 ALL 来:滑出动画到原始位置;普通切换:立即隐藏
|
|
669
|
-
if (fromAll) {
|
|
670
|
-
steps.push({
|
|
671
|
-
group: group,
|
|
672
|
-
fromY: group.position.y,
|
|
673
|
-
toY: origY2,
|
|
674
|
-
toVisible: true
|
|
675
|
-
});
|
|
676
|
-
} else {
|
|
677
|
-
group.visible = false;
|
|
678
|
-
group.position.y = -origY2 - 1;
|
|
679
|
-
}
|
|
644
|
+
// 离场层:立即消失(移到下方,不做动画)
|
|
645
|
+
group.visible = false;
|
|
646
|
+
var origY = self.core.floorOriginalY[idx] || 0;
|
|
647
|
+
group.position.y = -origY - 1;
|
|
680
648
|
}
|
|
681
649
|
});
|
|
682
650
|
|
|
683
|
-
//
|
|
651
|
+
// 合并/覆盖已有动画:先停止当前帧再以新起止值启动
|
|
684
652
|
if (self.core.floorAnim && self.core.floorAnim.running) {
|
|
685
653
|
var cur = self.core.floorAnim;
|
|
686
654
|
var t = Math.min((Date.now() - cur.startTime) / cur.duration, 1);
|
|
687
|
-
var et = 1 - Math.pow(1 - t, 3);
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
655
|
+
var et = 1 - Math.pow(1 - t, 3); // easeOutCubic reverse
|
|
656
|
+
// 把每个 group 瞬移到当前动画帧的位置
|
|
657
|
+
for (var i = 0; i < cur.steps.length; i++) {
|
|
658
|
+
var cs = cur.steps[i];
|
|
659
|
+
cs.group.position.y = cs.fromY + (cs.toY - cs.fromY) * et;
|
|
691
660
|
}
|
|
692
661
|
}
|
|
693
662
|
|
|
@@ -699,50 +668,10 @@ KimapSDK.prototype.showSingleFloor = function(floorIndex) {
|
|
|
699
668
|
};
|
|
700
669
|
|
|
701
670
|
this._currentShowingFloorIndex = floorIndex;
|
|
702
|
-
|
|
703
|
-
// 退出 ALL
|
|
671
|
+
self.core._lastSingleFloorIndex = floorIndex;
|
|
672
|
+
// 退出 ALL 时:相机动画恢复到单楼层视角(保持当前位置,不重置)
|
|
704
673
|
if (self.core.cameraPitchState === 1) {
|
|
705
|
-
|
|
706
|
-
if (self.core.cameraPitchAnim && self.core.cameraPitchAnim.running) {
|
|
707
|
-
var cpa = self.core.cameraPitchAnim;
|
|
708
|
-
var tc = Math.min((Date.now() - cpa.startTime) / cpa.duration, 1);
|
|
709
|
-
var etc = easeInOutCubic(tc);
|
|
710
|
-
self.core.camera.position.lerpVectors(cpa.fromPos, cpa.toPos, etc);
|
|
711
|
-
self.core.camera.lookAt(
|
|
712
|
-
cpa.fromTarget.x + (cpa.toTarget.x - cpa.fromTarget.x) * etc,
|
|
713
|
-
cpa.fromTarget.y + (cpa.toTarget.y - cpa.fromTarget.y) * etc,
|
|
714
|
-
cpa.fromTarget.z + (cpa.toTarget.z - cpa.fromTarget.z) * etc
|
|
715
|
-
);
|
|
716
|
-
if (self.core.controls) self.core.controls.update();
|
|
717
|
-
self.core.cameraPitchAnim = null;
|
|
718
|
-
}
|
|
719
|
-
// 目标相机位置:单楼层 -60° 俯角,lookAt 稍偏高处
|
|
720
|
-
var floorMeshes = [];
|
|
721
|
-
self.floorGroups[floorIndex].traverse(function(child) {
|
|
722
|
-
if (child.isMesh) floorMeshes.push(child);
|
|
723
|
-
});
|
|
724
|
-
var box2 = new THREE.Box3();
|
|
725
|
-
floorMeshes.forEach(function(m) { box2.expandByObject(m); });
|
|
726
|
-
var ctr = new THREE.Vector3();
|
|
727
|
-
var sz = new THREE.Vector3();
|
|
728
|
-
box2.getCenter(ctr);
|
|
729
|
-
box2.getSize(sz);
|
|
730
|
-
var ms = Math.max(sz.x, sz.z);
|
|
731
|
-
var d = ms * 1.8;
|
|
732
|
-
var lookAtH = new THREE.Vector3(ctr.x, ctr.y + ms * 0.15, ctr.z);
|
|
733
|
-
var toPos = new THREE.Vector3(lookAtH.x, lookAtH.y - d * 0.866, lookAtH.z + d * 0.5);
|
|
734
|
-
var fromCP = self.core.camera.position.clone();
|
|
735
|
-
var fromTgt = self.core.lookAtTarget ? self.core.lookAtTarget.clone() : lookAtH.clone();
|
|
736
|
-
self.core.cameraPitchAnim = {
|
|
737
|
-
running: true,
|
|
738
|
-
startTime: Date.now(),
|
|
739
|
-
duration: 600,
|
|
740
|
-
fromPos: fromCP,
|
|
741
|
-
toPos: toPos,
|
|
742
|
-
fromTarget: fromTgt,
|
|
743
|
-
toTarget: lookAtH
|
|
744
|
-
};
|
|
745
|
-
self.core.cameraPitchState = 0;
|
|
674
|
+
self.core.animateCameraToFloorView(600);
|
|
746
675
|
}
|
|
747
676
|
};
|
|
748
677
|
|
package/src/core/SceneCore.js
CHANGED
|
@@ -75,6 +75,7 @@ function SceneCore(config) {
|
|
|
75
75
|
this.cameraPitchState = 0; // 0=正常视角, 1=ALL外景俯视
|
|
76
76
|
this.cameraPrePitchPos = null; // 俯仰动画前的相机位置
|
|
77
77
|
this.cameraPrePitchTarget = null; // 俯仰动画前的 controls.target
|
|
78
|
+
this._prevCameraPitchState = 0; // 上一帧的相机状态(用于检测状态变化触发动画)
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
/**
|
|
@@ -532,23 +533,16 @@ SceneCore.prototype.adjustCameraToFloor = function(floorIndex) {
|
|
|
532
533
|
box.getCenter(center);
|
|
533
534
|
box.getSize(size);
|
|
534
535
|
var maxSize = Math.max(size.x, size.z);
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
// camera.z - lookAt.z = dist * cos(-60°) = dist * 0.5
|
|
541
|
-
this.camera.position.set(
|
|
542
|
-
lookAtTgt.x,
|
|
543
|
-
lookAtTgt.y - dist * 0.866,
|
|
544
|
-
lookAtTgt.z + dist * 0.5
|
|
545
|
-
);
|
|
536
|
+
var distance = maxSize * 1.5;
|
|
537
|
+
|
|
538
|
+
// -60° 俯角(与 ALL -45° 区分,单楼层更俯视)
|
|
539
|
+
this.camera.position.set(center.x, center.y - distance * 1.732, center.z + distance);
|
|
540
|
+
var lookAtTgt = new THREE.Vector3(center.x, center.y, center.z);
|
|
546
541
|
this.camera.lookAt(lookAtTgt);
|
|
547
542
|
if (this.controls) {
|
|
548
543
|
this.controls.target.copy(lookAtTgt);
|
|
549
544
|
this.controls.update();
|
|
550
545
|
}
|
|
551
|
-
// 记录当前 lookAt 目标(ALL 退场恢复用)
|
|
552
546
|
this.camera.lookAtTarget = lookAtTgt;
|
|
553
547
|
this.coordinateSystem.maxX = size.x;
|
|
554
548
|
this.coordinateSystem.maxY = size.z;
|
|
@@ -557,6 +551,14 @@ SceneCore.prototype.adjustCameraToFloor = function(floorIndex) {
|
|
|
557
551
|
}
|
|
558
552
|
};
|
|
559
553
|
|
|
554
|
+
/**
|
|
555
|
+
* 首次加载 / ALL 退出时:单楼层 -60° 俯角相机定位(独立方法,不改变现有 adjustCameraToFloor)
|
|
556
|
+
* @param {number} floorIndex
|
|
557
|
+
*/
|
|
558
|
+
SceneCore.prototype.adjustCameraToSingleFloorView = function(floorIndex) {
|
|
559
|
+
this.adjustCameraToFloor(floorIndex);
|
|
560
|
+
};
|
|
561
|
+
|
|
560
562
|
/**
|
|
561
563
|
* 加载 Kimap 加密文件(内部方法)
|
|
562
564
|
* @private
|
|
@@ -1289,7 +1291,11 @@ SceneCore.prototype.tickAnimations = function(deltaMs) {
|
|
|
1289
1291
|
this.controls.target.copy(toTarget);
|
|
1290
1292
|
this.controls.update();
|
|
1291
1293
|
}
|
|
1294
|
+
// 动画结束:读取引入时保存的 targetState 归位
|
|
1295
|
+
var finishedTargetState = this.cameraPitchAnim ? this.cameraPitchAnim.targetState : 0;
|
|
1292
1296
|
this.cameraPitchAnim = null;
|
|
1297
|
+
this.cameraPitchState = finishedTargetState;
|
|
1298
|
+
this.camera.lookAtTarget = toTarget.clone();
|
|
1293
1299
|
}
|
|
1294
1300
|
}
|
|
1295
1301
|
};
|
|
@@ -1349,12 +1355,12 @@ SceneCore.prototype.animateCameraToAllView = function(duration) {
|
|
|
1349
1355
|
this.cameraPrePitchPos = this.camera.position.clone();
|
|
1350
1356
|
this.cameraPrePitchTarget = this.controls ? this.controls.target.clone() : center.clone();
|
|
1351
1357
|
|
|
1352
|
-
//
|
|
1353
|
-
// camera.z - center.z = distance × cos(-
|
|
1354
|
-
var dist = maxSize *
|
|
1358
|
+
// ALL 外景俯角 -25°:camera.y - center.y = distance × sin(-25°) ≈ -distance × 0.423
|
|
1359
|
+
// camera.z - center.z = distance × cos(-25°) ≈ distance × 0.906
|
|
1360
|
+
var dist = maxSize * 2;
|
|
1355
1361
|
var fromPos = this.camera.position.clone();
|
|
1356
1362
|
var fromTarget = this.controls ? this.controls.target.clone() : center.clone();
|
|
1357
|
-
var toPos = new THREE.Vector3(center.x, center.y - dist * 0.
|
|
1363
|
+
var toPos = new THREE.Vector3(center.x, center.y - dist * 0.423, center.z + dist * 0.906);
|
|
1358
1364
|
var toTarget = new THREE.Vector3(center.x, center.y, center.z);
|
|
1359
1365
|
|
|
1360
1366
|
this.cameraPitchAnim = {
|
|
@@ -1364,7 +1370,8 @@ SceneCore.prototype.animateCameraToAllView = function(duration) {
|
|
|
1364
1370
|
fromPos: fromPos,
|
|
1365
1371
|
toPos: toPos,
|
|
1366
1372
|
fromTarget: fromTarget,
|
|
1367
|
-
toTarget: toTarget
|
|
1373
|
+
toTarget: toTarget,
|
|
1374
|
+
targetState: 1 // 动画结束后 cameraPitchState 应为 1(ALL 状态)
|
|
1368
1375
|
};
|
|
1369
1376
|
this.cameraPitchState = 1;
|
|
1370
1377
|
};
|
|
@@ -1392,22 +1399,49 @@ SceneCore.prototype.animateCameraToFloorView = function(duration) {
|
|
|
1392
1399
|
this.cameraPitchAnim = null;
|
|
1393
1400
|
}
|
|
1394
1401
|
|
|
1395
|
-
//
|
|
1396
|
-
var
|
|
1397
|
-
var
|
|
1402
|
+
// 计算当前单楼层中心(-60° 单楼层俯角,不压低)
|
|
1403
|
+
var floorIdx = this._lastSingleFloorIndex !== undefined ? this._lastSingleFloorIndex : 0;
|
|
1404
|
+
var floorGroup = this.floorGroups[floorIdx];
|
|
1405
|
+
var toTarget, toPos, dist, maxSize;
|
|
1406
|
+
|
|
1407
|
+
if (floorGroup) {
|
|
1408
|
+
var meshes = [];
|
|
1409
|
+
floorGroup.traverse(function(child) { if (child.isMesh) meshes.push(child); });
|
|
1410
|
+
if (meshes.length > 0) {
|
|
1411
|
+
var box = new THREE.Box3();
|
|
1412
|
+
meshes.forEach(function(mesh) { box.expandByObject(mesh); });
|
|
1413
|
+
toTarget = new THREE.Vector3();
|
|
1414
|
+
var size = new THREE.Vector3();
|
|
1415
|
+
box.getCenter(toTarget);
|
|
1416
|
+
box.getSize(size);
|
|
1417
|
+
maxSize = Math.max(size.x, size.z);
|
|
1418
|
+
dist = maxSize * 1.5;
|
|
1419
|
+
// -60° 俯角,与 ALL -45° 区分
|
|
1420
|
+
toPos = new THREE.Vector3(toTarget.x, toTarget.y - dist * 1.732, toTarget.z + dist);
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
if (!toPos) {
|
|
1425
|
+
toTarget = this.camera.lookAtTarget || this.camera.position.clone();
|
|
1426
|
+
toPos = this.camera.position.clone();
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
var fromPos = this.camera.position.clone();
|
|
1430
|
+
var fromTarget = this.camera.lookAtTarget ? this.camera.lookAtTarget.clone() : toTarget.clone();
|
|
1398
1431
|
|
|
1399
1432
|
this.cameraPitchAnim = {
|
|
1400
1433
|
running: true,
|
|
1401
1434
|
startTime: Date.now(),
|
|
1402
1435
|
duration: duration,
|
|
1403
|
-
fromPos:
|
|
1436
|
+
fromPos: fromPos,
|
|
1404
1437
|
toPos: toPos,
|
|
1405
|
-
fromTarget:
|
|
1438
|
+
fromTarget: fromTarget,
|
|
1406
1439
|
toTarget: toTarget
|
|
1407
1440
|
};
|
|
1408
1441
|
this.cameraPitchState = 0;
|
|
1409
1442
|
this.cameraPrePitchPos = null;
|
|
1410
1443
|
this.cameraPrePitchTarget = null;
|
|
1444
|
+
this.camera.lookAtTarget = toTarget.clone();
|
|
1411
1445
|
};
|
|
1412
1446
|
|
|
1413
1447
|
module.exports = SceneCore;
|