@ericchen1990/pano-view 3.6.1 → 3.6.3
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/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/dist/index.cjs +150 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +150 -45
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -879,7 +879,7 @@ function TourPlayer() {
|
|
|
879
879
|
|
|
880
880
|
The two deprecated auto-rotation handle methods (`startAutoRotate`, `stopAutoRotate`) remain for compatibility. Mouse, touch, and keyboard input are enabled by default — you do not need to render control components for ordinary viewing. Render `MouseControls`, `TouchControls`, or `KeyboardControls` only to override properties (the child replaces that channel's default instance). Tune shared behaviour through `controls` (`inertia`, `invert`, `bouncingLimits`, `fovSpeed`, `frictionStop`, `rotateDamping`, `zoomDamping`, and top-level `rotateSpeed` / `zoomSpeed`). Disable a channel with `controls.mouse` / `touch` / `keyboard` set to `false`, or pass an options object (including `enabled`) to override defaults without mounting a child. Auto-rotation is off until you render `AutoRotate`. A default context menu (Reset view / Enter fullscreen) is also mounted — see [`PanoContextMenu`](#panocontextmenu).
|
|
881
881
|
|
|
882
|
-
Mouse, pen, and single-touch drags anchor the grabbed panorama point and update rotation once per render frame, with a short time-based filter (about 10ms of following delay during steady movement) to smooth uneven input samples. The grabbed point aligns
|
|
882
|
+
Mouse, pen, and single-touch drags anchor the grabbed panorama point and update rotation once per render frame, with a short time-based filter (about 10ms of following delay during steady movement) to smooth uneven input samples. The grabbed point aligns once movement settles, and releasing the pointer completes that alignment immediately. Flick inertia follows the latest pointer motion, so a pause before release does not continue an earlier flick. View limits and positions near the poles can restrict tracking. The default `rotateSpeed` of `0.35` gives 1:1 tracking; other values scale pointer displacement relative to it, `0` disables rotation, and `invert` reverses direction. The separate `rotateDamping` setting does not apply during anchored drags; release inertia is retained. Pinch and wheel zoom continue to follow the target FOV smoothly.
|
|
883
883
|
|
|
884
884
|
Other rotation input and zoom update a target view that the camera follows smoothly. `rotateDamping` and `zoomDamping` control that following speed in seconds^-1 (defaults: `14` and `16` respectively); smaller positive values make the camera approach the target more gradually, while `0` disables smoothing for that axis. Both values must be non-negative finite numbers. Imperative `setView()` and `reset()` remain immediate.
|
|
885
885
|
|
package/README.zh-CN.md
CHANGED
|
@@ -852,7 +852,7 @@ function TourPlayer() {
|
|
|
852
852
|
|
|
853
853
|
两个已废弃的自动旋转方法(`startAutoRotate`、`stopAutoRotate`)继续保留以兼容。鼠标、触控与键盘输入默认启用 — 普通浏览无需再渲染控件组件。仅当需要覆盖属性时渲染 `MouseControls`、`TouchControls` 或 `KeyboardControls`(子组件会替换该通道的默认实例)。通过 `controls` 调节共享行为(`inertia`、`invert`、`bouncingLimits`、`fovSpeed`、`frictionStop`、`rotateDamping`、`zoomDamping`,以及顶层的 `rotateSpeed` / `zoomSpeed`)。将 `controls.mouse` / `touch` / `keyboard` 设为 `false` 可关闭某通道,或传入选项对象(含 `enabled`)在不挂载子组件的情况下覆盖默认值。自动旋转在渲染 `AutoRotate` 之前处于关闭状态。默认右键菜单(重置视图 / 进入全屏)也会挂载 — 见 [`PanoContextMenu`](#panocontextmenu)。
|
|
854
854
|
|
|
855
|
-
鼠标、笔和单指拖拽会锚定按下的全景点,并在每个渲染帧更新旋转;使用短暂的时间平滑吸收输入采样的波动(匀速移动时约 10ms
|
|
855
|
+
鼠标、笔和单指拖拽会锚定按下的全景点,并在每个渲染帧更新旋转;使用短暂的时间平滑吸收输入采样的波动(匀速移动时约 10ms 跟随延迟)。指针停住并收敛后,按下点会与指针对齐;松手时也会立刻完成这次对齐。甩动惯性只跟随最近一段指针运动,松手前如果已经停住,不会把更早的速度继续带出去。视角边界或极点附近可能限制跟随。`rotateSpeed` 默认 `0.35` 表示 1:1 跟随,其他值按其相对倍率调整指针位移,`0` 禁止旋转;`invert` 反转方向。双指缩放和滚轮继续更新目标 FOV,相机平滑跟随。拖拽释放后保留惯性。`rotateDamping` 与 `zoomDamping` 控制跟随速度(旋转平滑不作用于锚定拖拽期间),单位为秒⁻¹(默认分别为 `14` 与 `16`);较小的正值使相机更缓慢地接近目标视角,`0` 表示该轴不做平滑。两者必须为非负有限数。命令式 `setView()` 与 `reset()` 仍为即时生效。
|
|
856
856
|
|
|
857
857
|
画布光标默认为 `grab`,鼠标拖拽时为 `grabbing`,悬停在可交互热点上为 `pointer`,拖拽热点时为 `move`。可通过 `cursors`(`default`、`dragging`、`hotspot`、`hotspotDragging`)覆盖,或传 `cursors={false}` 保持画布光标不变。热点可设置 `cursor`,仅替换该热点的悬停光标。
|
|
858
858
|
|
package/dist/index.cjs
CHANGED
|
@@ -2896,7 +2896,12 @@ var PanoramaViewRuntime = (0, import_react3.forwardRef)(function PanoramaViewRun
|
|
|
2896
2896
|
}
|
|
2897
2897
|
}
|
|
2898
2898
|
markDirty();
|
|
2899
|
-
|
|
2899
|
+
const releaseVelocity = applyOptions?.velocity;
|
|
2900
|
+
if (!gyroControlsView && releaseVelocity && Number.isFinite(releaseVelocity.yaw) && Number.isFinite(releaseVelocity.pitch)) {
|
|
2901
|
+
yawVelocityRef.current = releaseVelocity.yaw;
|
|
2902
|
+
pitchVelocityRef.current = releaseVelocity.pitch;
|
|
2903
|
+
lastVelocitySampleAtRef.current = performance.now();
|
|
2904
|
+
} else if (applyOptions?.recordVelocity && !gyroControlsView) {
|
|
2900
2905
|
const now = performance.now();
|
|
2901
2906
|
const previousAt = lastVelocitySampleAtRef.current;
|
|
2902
2907
|
const elapsed = previousAt === null ? 1 / 60 : Math.max((now - previousAt) / 1e3, 1 / 120);
|
|
@@ -3736,6 +3741,26 @@ var import_react9 = require("react");
|
|
|
3736
3741
|
var import_three2 = require("three");
|
|
3737
3742
|
var DEFAULT_POINTER_DRAG_SPEED = 0.35;
|
|
3738
3743
|
var POINTER_FOLLOW_TIME_SECONDS = 0.01;
|
|
3744
|
+
var MIN_VELOCITY_SAMPLE_SECONDS = 1 / 120;
|
|
3745
|
+
function pointerReleaseVelocity(samples, releasedAt, solve, maxAgeMs = POINTER_VELOCITY_MAX_AGE_MS) {
|
|
3746
|
+
if (samples.length < 2) return { yaw: 0, pitch: 0 };
|
|
3747
|
+
const newest = samples[samples.length - 1];
|
|
3748
|
+
if (releasedAt < newest.at || releasedAt - newest.at > maxAgeMs) return { yaw: 0, pitch: 0 };
|
|
3749
|
+
let oldest = newest;
|
|
3750
|
+
for (let index = samples.length - 1; index >= 0; index -= 1) {
|
|
3751
|
+
const sample = samples[index];
|
|
3752
|
+
if (releasedAt - sample.at <= maxAgeMs) oldest = sample;
|
|
3753
|
+
else break;
|
|
3754
|
+
}
|
|
3755
|
+
if (oldest === newest) return { yaw: 0, pitch: 0 };
|
|
3756
|
+
const elapsed = Math.max((newest.at - oldest.at) / 1e3, MIN_VELOCITY_SAMPLE_SECONDS);
|
|
3757
|
+
const from = solve(oldest);
|
|
3758
|
+
const to = solve(newest);
|
|
3759
|
+
return {
|
|
3760
|
+
yaw: normalizeViewYaw(to.yaw - from.yaw) / elapsed,
|
|
3761
|
+
pitch: (to.pitch - from.pitch) / elapsed
|
|
3762
|
+
};
|
|
3763
|
+
}
|
|
3739
3764
|
var PointerDragAnchor = class {
|
|
3740
3765
|
constructor(start, origin, rect, projection) {
|
|
3741
3766
|
this.start = start;
|
|
@@ -3744,12 +3769,18 @@ var PointerDragAnchor = class {
|
|
|
3744
3769
|
this.projection = projection;
|
|
3745
3770
|
this.local = new import_three2.Vector3();
|
|
3746
3771
|
this.rotation = new import_three2.Euler(0, 0, 0, "YXZ");
|
|
3747
|
-
|
|
3772
|
+
const startRay = this.ray(start).clone();
|
|
3773
|
+
this.baseAzimuth = Math.atan2(startRay.x, -startRay.z);
|
|
3774
|
+
this.baseElevation = Math.atan2(startRay.y, -startRay.z);
|
|
3775
|
+
this.anchor = startRay.clone().applyEuler(this.rotation.set(
|
|
3748
3776
|
import_three2.MathUtils.degToRad(origin.pitch),
|
|
3749
3777
|
import_three2.MathUtils.degToRad(-origin.yaw),
|
|
3750
3778
|
0,
|
|
3751
3779
|
"YXZ"
|
|
3752
3780
|
));
|
|
3781
|
+
const originPitch = import_three2.MathUtils.degToRad(origin.pitch);
|
|
3782
|
+
const roots = this.pitchRoots(startRay, originPitch);
|
|
3783
|
+
this.useSupplementary = Math.abs(roots.supplementary - originPitch) + 1e-6 < Math.abs(roots.principal - originPitch);
|
|
3753
3784
|
}
|
|
3754
3785
|
ray(point) {
|
|
3755
3786
|
return this.local.set(
|
|
@@ -3758,6 +3789,21 @@ var PointerDragAnchor = class {
|
|
|
3758
3789
|
0.5
|
|
3759
3790
|
).applyMatrix4(this.projection.projectionMatrixInverse).normalize();
|
|
3760
3791
|
}
|
|
3792
|
+
/** Pitch roots of the level-camera constraint. The supplementary root is unwrapped toward the press. */
|
|
3793
|
+
pitchRoots(ray, originPitch) {
|
|
3794
|
+
const latitude = Math.asin(import_three2.MathUtils.clamp(
|
|
3795
|
+
this.anchor.y / Math.max(Math.hypot(ray.y, ray.z), 1e-12),
|
|
3796
|
+
-1,
|
|
3797
|
+
1
|
|
3798
|
+
));
|
|
3799
|
+
const offset = Math.atan2(ray.y, -ray.z);
|
|
3800
|
+
const principal = latitude - offset;
|
|
3801
|
+
const turned = Math.PI - latitude - offset;
|
|
3802
|
+
return {
|
|
3803
|
+
principal,
|
|
3804
|
+
supplementary: originPitch + Math.atan2(Math.sin(turned - originPitch), Math.cos(turned - originPitch))
|
|
3805
|
+
};
|
|
3806
|
+
}
|
|
3761
3807
|
solve(point, speed = DEFAULT_POINTER_DRAG_SPEED, invert = false) {
|
|
3762
3808
|
const multiplier = (Number.isFinite(speed) && speed >= 0 ? speed : DEFAULT_POINTER_DRAG_SPEED) / DEFAULT_POINTER_DRAG_SPEED * (invert ? -1 : 1);
|
|
3763
3809
|
if (multiplier === 0) return { yaw: 0, pitch: 0 };
|
|
@@ -3765,22 +3811,27 @@ var PointerDragAnchor = class {
|
|
|
3765
3811
|
x: this.start.x + (point.x - this.start.x) * multiplier,
|
|
3766
3812
|
y: this.start.y + (point.y - this.start.y) * multiplier
|
|
3767
3813
|
});
|
|
3768
|
-
const latitude = Math.asin(import_three2.MathUtils.clamp(this.anchor.y / Math.max(Math.hypot(ray.y, ray.z), 1e-12), -1, 1));
|
|
3769
|
-
const offset = Math.atan2(ray.y, -ray.z);
|
|
3770
3814
|
const originPitch = import_three2.MathUtils.degToRad(this.origin.pitch);
|
|
3771
|
-
const
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3815
|
+
const roots = this.pitchRoots(ray, originPitch);
|
|
3816
|
+
const exactPitch = import_three2.MathUtils.clamp(
|
|
3817
|
+
this.useSupplementary ? roots.supplementary : roots.principal,
|
|
3818
|
+
-Math.PI / 2,
|
|
3819
|
+
Math.PI / 2
|
|
3820
|
+
);
|
|
3821
|
+
const stablePitch = originPitch - (Math.atan2(ray.y, -ray.z) - this.baseElevation);
|
|
3822
|
+
const fromPole = Math.asin(Math.min(1, Math.hypot(this.anchor.x, this.anchor.z)));
|
|
3823
|
+
const pointerLock = import_three2.MathUtils.smoothstep(fromPole, import_three2.MathUtils.degToRad(8), import_three2.MathUtils.degToRad(18));
|
|
3824
|
+
const pitchTurn = Math.atan2(Math.sin(exactPitch - stablePitch), Math.cos(exactPitch - stablePitch));
|
|
3825
|
+
const pitch = import_three2.MathUtils.clamp(
|
|
3826
|
+
pointerLock >= 1 ? exactPitch : stablePitch + pointerLock * pitchTurn,
|
|
3827
|
+
-Math.PI / 2,
|
|
3828
|
+
Math.PI / 2
|
|
3829
|
+
);
|
|
3830
|
+
const pitchedZ = Math.sin(exactPitch) * ray.y + Math.cos(exactPitch) * ray.z;
|
|
3831
|
+
const exactYaw = Math.atan2(this.anchor.x, -this.anchor.z) - Math.atan2(ray.x, -pitchedZ);
|
|
3832
|
+
const stableYaw = import_three2.MathUtils.degToRad(this.origin.yaw) + Math.atan2(ray.x, -ray.z) - this.baseAzimuth;
|
|
3833
|
+
const yawTurn = Math.atan2(Math.sin(exactYaw - stableYaw), Math.cos(exactYaw - stableYaw));
|
|
3834
|
+
const yaw = import_three2.MathUtils.radToDeg(stableYaw + pointerLock * yawTurn);
|
|
3784
3835
|
return { yaw: normalizeViewYaw(yaw - this.origin.yaw), pitch: import_three2.MathUtils.radToDeg(pitch) - this.origin.pitch };
|
|
3785
3836
|
}
|
|
3786
3837
|
};
|
|
@@ -3793,8 +3844,11 @@ function createPointerDrag(camera, element, runtime, source) {
|
|
|
3793
3844
|
let lastPoint;
|
|
3794
3845
|
let fresh = false;
|
|
3795
3846
|
let lastFrameDelta = 1 / 60;
|
|
3847
|
+
let samples = [];
|
|
3848
|
+
let gestureSpeed = DEFAULT_POINTER_DRAG_SPEED;
|
|
3849
|
+
let gestureInvert = false;
|
|
3796
3850
|
const key = (rect) => `${rect.left},${rect.top},${rect.width},${rect.height},${camera.projectionMatrix.elements.join(",")}`;
|
|
3797
|
-
const
|
|
3851
|
+
const place = (point) => {
|
|
3798
3852
|
const handle = runtime();
|
|
3799
3853
|
displayed = { ...point };
|
|
3800
3854
|
lastPoint = { ...point };
|
|
@@ -3806,69 +3860,113 @@ function createPointerDrag(camera, element, runtime, source) {
|
|
|
3806
3860
|
projectionKey = key(rect);
|
|
3807
3861
|
anchor = new PointerDragAnchor(point, handle.getView(), rect, camera.clone());
|
|
3808
3862
|
};
|
|
3809
|
-
const
|
|
3863
|
+
const remember = (point, at) => {
|
|
3864
|
+
samples.push({ x: point.x, y: point.y, at });
|
|
3865
|
+
const cutoff = at - POINTER_VELOCITY_MAX_AGE_MS;
|
|
3866
|
+
while (samples.length > 2 && samples[0].at < cutoff) samples.shift();
|
|
3867
|
+
};
|
|
3868
|
+
const apply = (point, previous, speed, invert, recordVelocity, releaseVelocity) => {
|
|
3810
3869
|
const handle = runtime();
|
|
3811
3870
|
if (!handle) return;
|
|
3812
3871
|
const rect = element.getBoundingClientRect();
|
|
3813
3872
|
if (anchor && key(rect) !== projectionKey) {
|
|
3814
3873
|
const queued = pending;
|
|
3815
|
-
|
|
3874
|
+
place(displayed ?? previous);
|
|
3816
3875
|
pending = queued;
|
|
3817
3876
|
}
|
|
3877
|
+
const options = {
|
|
3878
|
+
recordVelocity: releaseVelocity ? false : recordVelocity,
|
|
3879
|
+
source,
|
|
3880
|
+
...releaseVelocity ? { velocity: releaseVelocity } : {}
|
|
3881
|
+
};
|
|
3818
3882
|
if (anchor) {
|
|
3819
3883
|
handle.applyViewDelta(anchor.solve(point, speed, invert), {
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
source
|
|
3884
|
+
...options,
|
|
3885
|
+
pointerOrigin: anchor.origin
|
|
3823
3886
|
});
|
|
3824
3887
|
} else {
|
|
3825
3888
|
handle.applyViewDelta({
|
|
3826
3889
|
yaw: -(point.x - previous.x) * 360 * speed / Math.max(rect.width, 1) * (invert ? -1 : 1),
|
|
3827
3890
|
pitch: (point.y - previous.y) * 180 * speed / Math.max(rect.height, 1) * (invert ? -1 : 1)
|
|
3828
|
-
},
|
|
3891
|
+
}, options);
|
|
3829
3892
|
}
|
|
3830
3893
|
};
|
|
3894
|
+
const valid = () => revision === (runtime()?.getPointerDragState().revision ?? -1) && !runtime()?.isInteractionLocked();
|
|
3895
|
+
const clear = () => {
|
|
3896
|
+
anchor = void 0;
|
|
3897
|
+
revision = -1;
|
|
3898
|
+
pending = void 0;
|
|
3899
|
+
displayed = void 0;
|
|
3900
|
+
samples = [];
|
|
3901
|
+
};
|
|
3831
3902
|
return {
|
|
3832
|
-
start,
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
displayed = void 0;
|
|
3903
|
+
start(point, at = performance.now()) {
|
|
3904
|
+
gestureSpeed = DEFAULT_POINTER_DRAG_SPEED;
|
|
3905
|
+
gestureInvert = false;
|
|
3906
|
+
samples = [];
|
|
3907
|
+
remember(point, at);
|
|
3908
|
+
place(point);
|
|
3839
3909
|
},
|
|
3910
|
+
valid,
|
|
3911
|
+
clear,
|
|
3840
3912
|
suspend: () => {
|
|
3841
3913
|
anchor = void 0;
|
|
3842
3914
|
pending = void 0;
|
|
3843
3915
|
displayed = void 0;
|
|
3916
|
+
samples = [];
|
|
3844
3917
|
},
|
|
3845
|
-
move(point, previous, speed, invert) {
|
|
3918
|
+
move(point, previous, speed, invert, at = performance.now()) {
|
|
3846
3919
|
fresh = true;
|
|
3920
|
+
gestureSpeed = speed;
|
|
3921
|
+
gestureInvert = invert;
|
|
3922
|
+
remember(point, at);
|
|
3847
3923
|
pending = { point, previous: lastPoint ?? previous, speed, invert };
|
|
3848
3924
|
},
|
|
3849
|
-
flush(deltaSeconds = lastFrameDelta, immediate = false) {
|
|
3850
|
-
lastFrameDelta = deltaSeconds;
|
|
3925
|
+
flush(deltaSeconds = lastFrameDelta, immediate = false, releaseVelocity) {
|
|
3926
|
+
if (deltaSeconds > 0) lastFrameDelta = deltaSeconds;
|
|
3851
3927
|
if (!pending) return;
|
|
3852
3928
|
const sample = pending;
|
|
3853
3929
|
if (!anchor || immediate) {
|
|
3854
3930
|
pending = void 0;
|
|
3855
|
-
apply(sample.point, sample.previous, sample.speed, sample.invert, fresh);
|
|
3931
|
+
apply(sample.point, sample.previous, sample.speed, sample.invert, fresh, releaseVelocity);
|
|
3856
3932
|
fresh = false;
|
|
3857
3933
|
lastPoint = sample.point;
|
|
3858
3934
|
displayed = sample.point;
|
|
3859
3935
|
return;
|
|
3860
3936
|
}
|
|
3937
|
+
const dt = deltaSeconds > 0 ? deltaSeconds : lastFrameDelta;
|
|
3861
3938
|
const previousDisplay = displayed ?? sample.previous;
|
|
3862
3939
|
const dx = sample.point.x - previousDisplay.x;
|
|
3863
3940
|
const dy = sample.point.y - previousDisplay.y;
|
|
3864
3941
|
const distance = Math.hypot(dx, dy);
|
|
3865
|
-
const ratio = distance > 0.01 ? POINTER_FOLLOW_TIME_SECONDS / (POINTER_FOLLOW_TIME_SECONDS +
|
|
3942
|
+
const ratio = distance > 0.01 ? POINTER_FOLLOW_TIME_SECONDS / (POINTER_FOLLOW_TIME_SECONDS + dt) : 0;
|
|
3866
3943
|
const point = { x: sample.point.x - dx * ratio, y: sample.point.y - dy * ratio };
|
|
3867
3944
|
apply(point, sample.previous, sample.speed, sample.invert, fresh);
|
|
3868
3945
|
fresh = false;
|
|
3869
3946
|
lastPoint = sample.point;
|
|
3870
3947
|
displayed = point;
|
|
3871
3948
|
if (ratio === 0) pending = void 0;
|
|
3949
|
+
},
|
|
3950
|
+
release() {
|
|
3951
|
+
const handle = runtime();
|
|
3952
|
+
if (!handle || !valid()) {
|
|
3953
|
+
clear();
|
|
3954
|
+
return;
|
|
3955
|
+
}
|
|
3956
|
+
const newestAt = samples[samples.length - 1]?.at ?? 0;
|
|
3957
|
+
const velocity = pointerReleaseVelocity(samples, Math.max(performance.now(), newestAt), (point) => {
|
|
3958
|
+
if (anchor) return anchor.solve(point, gestureSpeed, gestureInvert);
|
|
3959
|
+
const origin = samples[0] ?? point;
|
|
3960
|
+
const rect = element.getBoundingClientRect();
|
|
3961
|
+
const sign = gestureInvert ? -1 : 1;
|
|
3962
|
+
return {
|
|
3963
|
+
yaw: -(point.x - origin.x) * 360 * gestureSpeed / Math.max(rect.width, 1) * sign,
|
|
3964
|
+
pitch: (point.y - origin.y) * 180 * gestureSpeed / Math.max(rect.height, 1) * sign
|
|
3965
|
+
};
|
|
3966
|
+
});
|
|
3967
|
+
if (pending) this.flush(lastFrameDelta, true, velocity);
|
|
3968
|
+
else handle.applyViewDelta({}, { velocity, source });
|
|
3969
|
+
clear();
|
|
3872
3970
|
}
|
|
3873
3971
|
};
|
|
3874
3972
|
}
|
|
@@ -3884,6 +3982,9 @@ var BUTTON_FLAG = {
|
|
|
3884
3982
|
function resolveSpeed2(value, fallback) {
|
|
3885
3983
|
return Number.isFinite(value) && value >= 0 ? value : fallback;
|
|
3886
3984
|
}
|
|
3985
|
+
function pointerAt(event) {
|
|
3986
|
+
return event.timeStamp > 0 ? event.timeStamp : performance.now();
|
|
3987
|
+
}
|
|
3887
3988
|
function resolveButtons(buttons) {
|
|
3888
3989
|
const list = buttons && buttons.length > 0 ? buttons : ["left"];
|
|
3889
3990
|
return new Set(list.map((button) => BUTTON_FLAG[button]));
|
|
@@ -3970,7 +4071,7 @@ function MouseControls({
|
|
|
3970
4071
|
});
|
|
3971
4072
|
element.setPointerCapture?.(event.pointerId);
|
|
3972
4073
|
syncActive();
|
|
3973
|
-
drag.start({ x: event.clientX, y: event.clientY });
|
|
4074
|
+
drag.start({ x: event.clientX, y: event.clientY }, pointerAt(event));
|
|
3974
4075
|
};
|
|
3975
4076
|
const onPointerMove = (event) => {
|
|
3976
4077
|
if (!isMouseLike(event)) {
|
|
@@ -3991,15 +4092,15 @@ function MouseControls({
|
|
|
3991
4092
|
};
|
|
3992
4093
|
pointersRef.current.set(event.pointerId, next);
|
|
3993
4094
|
const speed = resolveSpeed2(optionsRef.current.rotateSpeed, DEFAULT_ROTATE_SPEED2);
|
|
3994
|
-
drag.move(next, previous, speed, optionsRef.current.invert);
|
|
4095
|
+
drag.move(next, previous, speed, optionsRef.current.invert, pointerAt(event));
|
|
3995
4096
|
};
|
|
3996
4097
|
const releasePointer = (event) => {
|
|
3997
4098
|
if (!pointersRef.current.has(event.pointerId)) {
|
|
3998
4099
|
return;
|
|
3999
4100
|
}
|
|
4000
|
-
if (event.type === "pointerup") drag.
|
|
4101
|
+
if (event.type === "pointerup") drag.release();
|
|
4102
|
+
else drag.clear();
|
|
4001
4103
|
pointersRef.current.delete(event.pointerId);
|
|
4002
|
-
drag.clear();
|
|
4003
4104
|
if (element.hasPointerCapture?.(event.pointerId)) {
|
|
4004
4105
|
element.releasePointerCapture?.(event.pointerId);
|
|
4005
4106
|
}
|
|
@@ -5642,6 +5743,9 @@ function notifyScenesHost(host) {
|
|
|
5642
5743
|
var import_fiber8 = require("@react-three/fiber");
|
|
5643
5744
|
var import_react18 = require("react");
|
|
5644
5745
|
var DEFAULT_ROTATE_SPEED3 = 0.35;
|
|
5746
|
+
function pointerAt2(event) {
|
|
5747
|
+
return event.timeStamp > 0 ? event.timeStamp : performance.now();
|
|
5748
|
+
}
|
|
5645
5749
|
function resolveSpeed3(value, fallback) {
|
|
5646
5750
|
return Number.isFinite(value) && value >= 0 ? value : fallback;
|
|
5647
5751
|
}
|
|
@@ -5710,7 +5814,7 @@ function TouchControls({
|
|
|
5710
5814
|
});
|
|
5711
5815
|
element.setPointerCapture?.(event.pointerId);
|
|
5712
5816
|
syncActive();
|
|
5713
|
-
drag.start({ x: event.clientX, y: event.clientY });
|
|
5817
|
+
drag.start({ x: event.clientX, y: event.clientY }, pointerAt2(event));
|
|
5714
5818
|
if (pointersRef.current.size >= 2) {
|
|
5715
5819
|
drag.suspend();
|
|
5716
5820
|
const [first, second] = Array.from(pointersRef.current.values());
|
|
@@ -5757,15 +5861,16 @@ function TouchControls({
|
|
|
5757
5861
|
return;
|
|
5758
5862
|
}
|
|
5759
5863
|
const speed = resolveSpeed3(optionsRef.current.rotateSpeed, DEFAULT_ROTATE_SPEED3);
|
|
5760
|
-
drag.move(next, previous, speed, optionsRef.current.invert);
|
|
5864
|
+
drag.move(next, previous, speed, optionsRef.current.invert, pointerAt2(event));
|
|
5761
5865
|
};
|
|
5762
5866
|
const releasePointer = (event) => {
|
|
5763
5867
|
if (!pointersRef.current.has(event.pointerId)) {
|
|
5764
5868
|
return;
|
|
5765
5869
|
}
|
|
5766
|
-
|
|
5870
|
+
const pinch = pointersRef.current.size >= 2;
|
|
5871
|
+
if (event.type === "pointerup" && !pinch) drag.release();
|
|
5872
|
+
else drag.clear();
|
|
5767
5873
|
pointersRef.current.delete(event.pointerId);
|
|
5768
|
-
drag.clear();
|
|
5769
5874
|
if (element.hasPointerCapture?.(event.pointerId)) {
|
|
5770
5875
|
element.releasePointerCapture?.(event.pointerId);
|
|
5771
5876
|
}
|
|
@@ -5774,7 +5879,7 @@ function TouchControls({
|
|
|
5774
5879
|
}
|
|
5775
5880
|
syncActive(event.type !== "pointerup");
|
|
5776
5881
|
const remaining = pointersRef.current.values().next().value;
|
|
5777
|
-
if (remaining) drag.start(remaining);
|
|
5882
|
+
if (remaining) drag.start(remaining, pointerAt2(event));
|
|
5778
5883
|
};
|
|
5779
5884
|
element.addEventListener("pointerdown", onPointerDown);
|
|
5780
5885
|
element.addEventListener("pointermove", onPointerMove);
|