@ericchen1990/pano-view 3.6.3 → 3.6.5
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.zh-CN.md +4 -4
- package/dist/index.cjs +347 -62
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +368 -80
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -3981,7 +3981,10 @@ function MouseControls({
|
|
|
3981
3981
|
const element = gl.domElement;
|
|
3982
3982
|
const drag = createPointerDrag(camera, element, () => controlsRef.current, "mouse");
|
|
3983
3983
|
const allowedButtons = resolveButtons(buttons);
|
|
3984
|
+
const pending = /* @__PURE__ */ new Set();
|
|
3985
|
+
let disposed = false;
|
|
3984
3986
|
const clearPointers = () => {
|
|
3987
|
+
pending.clear();
|
|
3985
3988
|
for (const pointerId of pointersRef.current.keys()) {
|
|
3986
3989
|
if (element.hasPointerCapture?.(pointerId)) {
|
|
3987
3990
|
element.releasePointerCapture?.(pointerId);
|
|
@@ -4007,6 +4010,25 @@ function MouseControls({
|
|
|
4007
4010
|
{ cancelled }
|
|
4008
4011
|
);
|
|
4009
4012
|
};
|
|
4013
|
+
const beginPointer = (event) => {
|
|
4014
|
+
if (disposed || controlsRef.current?.isInteractionLocked()) {
|
|
4015
|
+
return;
|
|
4016
|
+
}
|
|
4017
|
+
if (pointersRef.current.has(event.pointerId)) {
|
|
4018
|
+
return;
|
|
4019
|
+
}
|
|
4020
|
+
pointersRef.current.set(event.pointerId, {
|
|
4021
|
+
x: event.clientX,
|
|
4022
|
+
y: event.clientY,
|
|
4023
|
+
at: performance.now()
|
|
4024
|
+
});
|
|
4025
|
+
try {
|
|
4026
|
+
element.setPointerCapture?.(event.pointerId);
|
|
4027
|
+
} catch {
|
|
4028
|
+
}
|
|
4029
|
+
syncActive();
|
|
4030
|
+
drag.start({ x: event.clientX, y: event.clientY }, pointerAt(event));
|
|
4031
|
+
};
|
|
4010
4032
|
const onPointerDown = (event) => {
|
|
4011
4033
|
if (!isMouseLike(event)) {
|
|
4012
4034
|
return;
|
|
@@ -4018,14 +4040,14 @@ function MouseControls({
|
|
|
4018
4040
|
return;
|
|
4019
4041
|
}
|
|
4020
4042
|
event.preventDefault();
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4043
|
+
const pointerId = event.pointerId;
|
|
4044
|
+
pending.add(pointerId);
|
|
4045
|
+
queueMicrotask(() => {
|
|
4046
|
+
if (!pending.delete(pointerId)) {
|
|
4047
|
+
return;
|
|
4048
|
+
}
|
|
4049
|
+
beginPointer(event);
|
|
4025
4050
|
});
|
|
4026
|
-
element.setPointerCapture?.(event.pointerId);
|
|
4027
|
-
syncActive();
|
|
4028
|
-
drag.start({ x: event.clientX, y: event.clientY }, pointerAt(event));
|
|
4029
4051
|
};
|
|
4030
4052
|
const onPointerMove = (event) => {
|
|
4031
4053
|
if (!isMouseLike(event)) {
|
|
@@ -4049,6 +4071,7 @@ function MouseControls({
|
|
|
4049
4071
|
drag.move(next, previous, speed, optionsRef.current.invert, pointerAt(event));
|
|
4050
4072
|
};
|
|
4051
4073
|
const releasePointer = (event) => {
|
|
4074
|
+
pending.delete(event.pointerId);
|
|
4052
4075
|
if (!pointersRef.current.has(event.pointerId)) {
|
|
4053
4076
|
return;
|
|
4054
4077
|
}
|
|
@@ -4090,6 +4113,7 @@ function MouseControls({
|
|
|
4090
4113
|
element.addEventListener("lostpointercapture", releasePointer);
|
|
4091
4114
|
element.addEventListener("wheel", onWheel, { passive: false });
|
|
4092
4115
|
return () => {
|
|
4116
|
+
disposed = true;
|
|
4093
4117
|
validateDragRef.current = void 0;
|
|
4094
4118
|
element.removeEventListener("pointerdown", onPointerDown);
|
|
4095
4119
|
element.removeEventListener("pointermove", onPointerMove);
|
|
@@ -5607,6 +5631,12 @@ function vector3ToPanoPosition(vector) {
|
|
|
5607
5631
|
)
|
|
5608
5632
|
});
|
|
5609
5633
|
}
|
|
5634
|
+
function translateHotspotPosition(origin, from, to) {
|
|
5635
|
+
return normalizePanoPosition({
|
|
5636
|
+
yaw: origin.yaw + normalizePanoYaw(to.yaw - from.yaw),
|
|
5637
|
+
pitch: origin.pitch + (to.pitch - from.pitch)
|
|
5638
|
+
});
|
|
5639
|
+
}
|
|
5610
5640
|
|
|
5611
5641
|
// src/panorama-radius.ts
|
|
5612
5642
|
var DEFAULT_PANORAMA_RADIUS = 1e3;
|
|
@@ -5750,7 +5780,10 @@ function TouchControls({
|
|
|
5750
5780
|
useEffect11(() => {
|
|
5751
5781
|
const element = gl.domElement;
|
|
5752
5782
|
const drag = createPointerDrag(camera, element, () => controlsRef.current, "touch");
|
|
5783
|
+
const pending = /* @__PURE__ */ new Set();
|
|
5784
|
+
let disposed = false;
|
|
5753
5785
|
const clearPointers = () => {
|
|
5786
|
+
pending.clear();
|
|
5754
5787
|
for (const pointerId of pointersRef.current.keys()) {
|
|
5755
5788
|
if (element.hasPointerCapture?.(pointerId)) {
|
|
5756
5789
|
element.releasePointerCapture?.(pointerId);
|
|
@@ -5776,20 +5809,22 @@ function TouchControls({
|
|
|
5776
5809
|
{ cancelled }
|
|
5777
5810
|
);
|
|
5778
5811
|
};
|
|
5779
|
-
const
|
|
5780
|
-
if (
|
|
5812
|
+
const beginPointer = (event) => {
|
|
5813
|
+
if (disposed || controlsRef.current?.isInteractionLocked()) {
|
|
5781
5814
|
return;
|
|
5782
5815
|
}
|
|
5783
|
-
if (
|
|
5816
|
+
if (pointersRef.current.has(event.pointerId)) {
|
|
5784
5817
|
return;
|
|
5785
5818
|
}
|
|
5786
|
-
event.preventDefault();
|
|
5787
5819
|
pointersRef.current.set(event.pointerId, {
|
|
5788
5820
|
x: event.clientX,
|
|
5789
5821
|
y: event.clientY,
|
|
5790
5822
|
at: performance.now()
|
|
5791
5823
|
});
|
|
5792
|
-
|
|
5824
|
+
try {
|
|
5825
|
+
element.setPointerCapture?.(event.pointerId);
|
|
5826
|
+
} catch {
|
|
5827
|
+
}
|
|
5793
5828
|
syncActive();
|
|
5794
5829
|
drag.start({ x: event.clientX, y: event.clientY }, pointerAt2(event));
|
|
5795
5830
|
if (pointersRef.current.size >= 2) {
|
|
@@ -5798,6 +5833,23 @@ function TouchControls({
|
|
|
5798
5833
|
pinchDistanceRef.current = pointerDistance(first, second);
|
|
5799
5834
|
}
|
|
5800
5835
|
};
|
|
5836
|
+
const onPointerDown = (event) => {
|
|
5837
|
+
if (event.pointerType !== "touch") {
|
|
5838
|
+
return;
|
|
5839
|
+
}
|
|
5840
|
+
if (controlsRef.current?.isInteractionLocked()) {
|
|
5841
|
+
return;
|
|
5842
|
+
}
|
|
5843
|
+
event.preventDefault();
|
|
5844
|
+
const pointerId = event.pointerId;
|
|
5845
|
+
pending.add(pointerId);
|
|
5846
|
+
queueMicrotask(() => {
|
|
5847
|
+
if (!pending.delete(pointerId)) {
|
|
5848
|
+
return;
|
|
5849
|
+
}
|
|
5850
|
+
beginPointer(event);
|
|
5851
|
+
});
|
|
5852
|
+
};
|
|
5801
5853
|
const onPointerMove = (event) => {
|
|
5802
5854
|
if (event.pointerType !== "touch") {
|
|
5803
5855
|
return;
|
|
@@ -5841,6 +5893,7 @@ function TouchControls({
|
|
|
5841
5893
|
drag.move(next, previous, speed, optionsRef.current.invert, pointerAt2(event));
|
|
5842
5894
|
};
|
|
5843
5895
|
const releasePointer = (event) => {
|
|
5896
|
+
pending.delete(event.pointerId);
|
|
5844
5897
|
if (!pointersRef.current.has(event.pointerId)) {
|
|
5845
5898
|
return;
|
|
5846
5899
|
}
|
|
@@ -5864,6 +5917,7 @@ function TouchControls({
|
|
|
5864
5917
|
element.addEventListener("pointercancel", releasePointer);
|
|
5865
5918
|
element.addEventListener("lostpointercapture", releasePointer);
|
|
5866
5919
|
return () => {
|
|
5920
|
+
disposed = true;
|
|
5867
5921
|
validateDragRef.current = void 0;
|
|
5868
5922
|
element.removeEventListener("pointerdown", onPointerDown);
|
|
5869
5923
|
element.removeEventListener("pointermove", onPointerMove);
|
|
@@ -11505,13 +11559,104 @@ import {
|
|
|
11505
11559
|
EdgesGeometry,
|
|
11506
11560
|
MathUtils as MathUtils8,
|
|
11507
11561
|
Matrix4 as Matrix44,
|
|
11562
|
+
PerspectiveCamera as PerspectiveCamera8,
|
|
11508
11563
|
Plane,
|
|
11509
11564
|
PlaneGeometry as PlaneGeometry4,
|
|
11510
11565
|
Quaternion as Quaternion3,
|
|
11511
11566
|
Ray,
|
|
11567
|
+
Raycaster as Raycaster2,
|
|
11568
|
+
Vector2 as Vector24,
|
|
11512
11569
|
Vector3 as Vector316
|
|
11513
11570
|
} from "three";
|
|
11514
11571
|
|
|
11572
|
+
// src/hotspot/drag-session.ts
|
|
11573
|
+
var CLICK_SUPPRESS_MS = 1e3;
|
|
11574
|
+
function trackPointerDrag(source, element, pointerId, onMove, onEnd) {
|
|
11575
|
+
let stopped = false;
|
|
11576
|
+
const releaseCapture = () => {
|
|
11577
|
+
if (!element.hasPointerCapture?.(pointerId)) {
|
|
11578
|
+
return;
|
|
11579
|
+
}
|
|
11580
|
+
try {
|
|
11581
|
+
element.releasePointerCapture?.(pointerId);
|
|
11582
|
+
} catch {
|
|
11583
|
+
}
|
|
11584
|
+
};
|
|
11585
|
+
const stop = () => {
|
|
11586
|
+
if (stopped) {
|
|
11587
|
+
return;
|
|
11588
|
+
}
|
|
11589
|
+
stopped = true;
|
|
11590
|
+
source.removeEventListener("pointermove", onPointerMove, true);
|
|
11591
|
+
source.removeEventListener("pointerup", onPointerUp, true);
|
|
11592
|
+
source.removeEventListener("pointercancel", onPointerCancel, true);
|
|
11593
|
+
element.removeEventListener("lostpointercapture", onLostCapture);
|
|
11594
|
+
releaseCapture();
|
|
11595
|
+
};
|
|
11596
|
+
const finish = (event) => {
|
|
11597
|
+
if (stopped || event.pointerId !== pointerId) {
|
|
11598
|
+
return;
|
|
11599
|
+
}
|
|
11600
|
+
stop();
|
|
11601
|
+
onEnd(event);
|
|
11602
|
+
};
|
|
11603
|
+
const onPointerMove = (event) => {
|
|
11604
|
+
if (stopped || event.pointerId !== pointerId) {
|
|
11605
|
+
return;
|
|
11606
|
+
}
|
|
11607
|
+
try {
|
|
11608
|
+
event.preventDefault?.();
|
|
11609
|
+
} catch {
|
|
11610
|
+
}
|
|
11611
|
+
onMove(event);
|
|
11612
|
+
};
|
|
11613
|
+
const onPointerUp = (event) => {
|
|
11614
|
+
finish(event);
|
|
11615
|
+
};
|
|
11616
|
+
const onPointerCancel = (event) => {
|
|
11617
|
+
finish(event);
|
|
11618
|
+
};
|
|
11619
|
+
const onLostCapture = (event) => {
|
|
11620
|
+
if ((event.buttons ?? 0) > 0) {
|
|
11621
|
+
return;
|
|
11622
|
+
}
|
|
11623
|
+
finish(event);
|
|
11624
|
+
};
|
|
11625
|
+
try {
|
|
11626
|
+
element.setPointerCapture?.(pointerId);
|
|
11627
|
+
} catch {
|
|
11628
|
+
}
|
|
11629
|
+
source.addEventListener("pointermove", onPointerMove, true);
|
|
11630
|
+
source.addEventListener("pointerup", onPointerUp, true);
|
|
11631
|
+
source.addEventListener("pointercancel", onPointerCancel, true);
|
|
11632
|
+
element.addEventListener("lostpointercapture", onLostCapture);
|
|
11633
|
+
return stop;
|
|
11634
|
+
}
|
|
11635
|
+
var CAPTURE = { capture: true };
|
|
11636
|
+
function suppressFollowingClick(target) {
|
|
11637
|
+
let cleaned = false;
|
|
11638
|
+
const cleanup = () => {
|
|
11639
|
+
if (cleaned) {
|
|
11640
|
+
return;
|
|
11641
|
+
}
|
|
11642
|
+
cleaned = true;
|
|
11643
|
+
target.removeEventListener("click", swallowClick, CAPTURE);
|
|
11644
|
+
target.removeEventListener("pointerdown", cancel, CAPTURE);
|
|
11645
|
+
};
|
|
11646
|
+
const swallowClick = (event) => {
|
|
11647
|
+
event.preventDefault();
|
|
11648
|
+
event.stopPropagation();
|
|
11649
|
+
event.stopImmediatePropagation();
|
|
11650
|
+
cleanup();
|
|
11651
|
+
};
|
|
11652
|
+
const cancel = () => {
|
|
11653
|
+
cleanup();
|
|
11654
|
+
};
|
|
11655
|
+
target.addEventListener("click", swallowClick, CAPTURE);
|
|
11656
|
+
target.addEventListener("pointerdown", cancel, CAPTURE);
|
|
11657
|
+
setTimeout(cleanup, CLICK_SUPPRESS_MS);
|
|
11658
|
+
}
|
|
11659
|
+
|
|
11515
11660
|
// src/hotspot/hotspot-tooltip.tsx
|
|
11516
11661
|
import { useEffect as useEffect23, useMemo as useMemo18, useState as useState12 } from "react";
|
|
11517
11662
|
|
|
@@ -11780,6 +11925,21 @@ function fixedScaleFactor(cameraFov, referenceFov) {
|
|
|
11780
11925
|
const safeReferenceFov = MathUtils6.clamp(referenceFov, 1, 179);
|
|
11781
11926
|
return Math.tan(MathUtils6.degToRad(cameraFov) / 2) / Math.tan(MathUtils6.degToRad(safeReferenceFov) / 2);
|
|
11782
11927
|
}
|
|
11928
|
+
function selectionFrameScale(worldScaleX, worldScaleY, cameraSpaceDepth, fovDegrees, viewportHeight, outsetPixels) {
|
|
11929
|
+
const pixels = Number.isFinite(outsetPixels) && outsetPixels > 0 ? outsetPixels : 0;
|
|
11930
|
+
const depth = Number.isFinite(cameraSpaceDepth) ? Math.max(cameraSpaceDepth, 1e-4) : 1e-4;
|
|
11931
|
+
const height = Number.isFinite(viewportHeight) ? Math.max(viewportHeight, 1) : 1;
|
|
11932
|
+
const fov = Number.isFinite(fovDegrees) ? MathUtils6.clamp(fovDegrees, 1, 179) : 75;
|
|
11933
|
+
const pixelsPerWorldUnit = height / (2 * Math.tan(MathUtils6.degToRad(fov) * 0.5) * depth);
|
|
11934
|
+
const axis = (worldScale) => {
|
|
11935
|
+
const pixelsPerLocalUnit = pixelsPerWorldUnit * Math.abs(worldScale);
|
|
11936
|
+
if (pixelsPerLocalUnit < 1e-4) {
|
|
11937
|
+
return 1;
|
|
11938
|
+
}
|
|
11939
|
+
return 1 + 2 * pixels / pixelsPerLocalUnit;
|
|
11940
|
+
};
|
|
11941
|
+
return [axis(worldScaleX), axis(worldScaleY)];
|
|
11942
|
+
}
|
|
11783
11943
|
|
|
11784
11944
|
// src/hotspot/hotspot-stroke-line.tsx
|
|
11785
11945
|
import { Line } from "@react-three/drei";
|
|
@@ -11866,6 +12026,11 @@ var DEFAULT_REFERENCE_FOV = 75;
|
|
|
11866
12026
|
var MIN_ANGULAR_SIZE = 0.01;
|
|
11867
12027
|
var MAX_ANGULAR_SIZE = 179;
|
|
11868
12028
|
var DRAG_EPSILON_DEGREES = 1e-3;
|
|
12029
|
+
var SELECTION_BORDER_WIDTH = 3;
|
|
12030
|
+
var SELECTION_BORDER_GAP = 3;
|
|
12031
|
+
var SELECTION_BORDER_OUTSET = SELECTION_BORDER_GAP + SELECTION_BORDER_WIDTH / 2;
|
|
12032
|
+
var SELECTION_CAMERA_POSITION = new Vector316();
|
|
12033
|
+
var SELECTION_WORLD_SCALE = new Vector316();
|
|
11869
12034
|
var SELECTION_BORDER_POINTS = [
|
|
11870
12035
|
[-0.5, -0.5, 1e-3],
|
|
11871
12036
|
[0.5, -0.5, 1e-3],
|
|
@@ -11953,6 +12118,34 @@ function angularDistance(a, b) {
|
|
|
11953
12118
|
const bVector = panoPositionToVector3(b);
|
|
11954
12119
|
return MathUtils8.radToDeg(aVector.angleTo(bVector));
|
|
11955
12120
|
}
|
|
12121
|
+
var DRAG_POINTER = new Vector24();
|
|
12122
|
+
var DRAG_RAYCASTER = new Raycaster2();
|
|
12123
|
+
function aimDragRaycaster(event, element, camera) {
|
|
12124
|
+
const rect = element.getBoundingClientRect();
|
|
12125
|
+
if (!(rect.width > 0) || !(rect.height > 0)) {
|
|
12126
|
+
return false;
|
|
12127
|
+
}
|
|
12128
|
+
DRAG_POINTER.set(
|
|
12129
|
+
(event.clientX - rect.left) / rect.width * 2 - 1,
|
|
12130
|
+
-((event.clientY - rect.top) / rect.height) * 2 + 1
|
|
12131
|
+
);
|
|
12132
|
+
camera.updateMatrixWorld();
|
|
12133
|
+
DRAG_RAYCASTER.setFromCamera(DRAG_POINTER, camera);
|
|
12134
|
+
return true;
|
|
12135
|
+
}
|
|
12136
|
+
function pointerToPanoPosition(event, element, camera) {
|
|
12137
|
+
if (!aimDragRaycaster(event, element, camera)) {
|
|
12138
|
+
return null;
|
|
12139
|
+
}
|
|
12140
|
+
return vector3ToPanoPosition(DRAG_RAYCASTER.ray.direction);
|
|
12141
|
+
}
|
|
12142
|
+
function pointerHitsHotspot(event, element, camera, group) {
|
|
12143
|
+
if (!group || !aimDragRaycaster(event, element, camera)) {
|
|
12144
|
+
return false;
|
|
12145
|
+
}
|
|
12146
|
+
group.updateMatrixWorld(true);
|
|
12147
|
+
return DRAG_RAYCASTER.intersectObject(group, true).length > 0;
|
|
12148
|
+
}
|
|
11956
12149
|
function isTooltipOpen(trigger, hovered, focused, pinned) {
|
|
11957
12150
|
switch (trigger) {
|
|
11958
12151
|
case "always":
|
|
@@ -12148,6 +12341,24 @@ function updateTooltipAnchor(anchor, group, placement, useAngularScale, camera,
|
|
|
12148
12341
|
}
|
|
12149
12342
|
setTooltipAnchorOnLocalBox(anchor, placement, -0.5, 0.5, -0.5, 0.5);
|
|
12150
12343
|
}
|
|
12344
|
+
function placeSelectionFrame(frame, group, camera, viewportHeight) {
|
|
12345
|
+
if (!frame) {
|
|
12346
|
+
return;
|
|
12347
|
+
}
|
|
12348
|
+
group.getWorldScale(SELECTION_WORLD_SCALE);
|
|
12349
|
+
SELECTION_CAMERA_POSITION.setFromMatrixPosition(group.matrixWorld).applyMatrix4(
|
|
12350
|
+
camera.matrixWorldInverse
|
|
12351
|
+
);
|
|
12352
|
+
const [scaleX, scaleY] = selectionFrameScale(
|
|
12353
|
+
SELECTION_WORLD_SCALE.x,
|
|
12354
|
+
SELECTION_WORLD_SCALE.y,
|
|
12355
|
+
-SELECTION_CAMERA_POSITION.z,
|
|
12356
|
+
camera instanceof PerspectiveCamera8 ? camera.fov : DEFAULT_REFERENCE_FOV,
|
|
12357
|
+
viewportHeight,
|
|
12358
|
+
SELECTION_BORDER_OUTSET
|
|
12359
|
+
);
|
|
12360
|
+
frame.scale.set(scaleX, scaleY, 1);
|
|
12361
|
+
}
|
|
12151
12362
|
function HotspotAnchor({
|
|
12152
12363
|
id,
|
|
12153
12364
|
position,
|
|
@@ -12187,10 +12398,13 @@ function HotspotAnchor({
|
|
|
12187
12398
|
const hotspotTargetRegistry = useContext21(HotspotTargetRegistryContext);
|
|
12188
12399
|
const eventBus = useContext21(PanoEventBusContext);
|
|
12189
12400
|
const cursorApi = usePanoCursor();
|
|
12190
|
-
const { camera, size } = useThree19();
|
|
12401
|
+
const { camera, gl, size } = useThree19();
|
|
12191
12402
|
const groupRef = useRef25(null);
|
|
12403
|
+
const selectionFrameRef = useRef25(null);
|
|
12192
12404
|
const tooltipAnchorRef = useRef25(null);
|
|
12193
12405
|
const dragStateRef = useRef25(null);
|
|
12406
|
+
const updateDragRef = useRef25(() => void 0);
|
|
12407
|
+
const endDragRef = useRef25(() => void 0);
|
|
12194
12408
|
const suppressNextClickRef = useRef25(false);
|
|
12195
12409
|
const [hovered, setHovered] = useState13(false);
|
|
12196
12410
|
const [dragging, setDragging] = useState13(false);
|
|
@@ -12260,7 +12474,9 @@ function HotspotAnchor({
|
|
|
12260
12474
|
const cursorClaimId = hotspotCursorClaimId(id);
|
|
12261
12475
|
useEffect24(
|
|
12262
12476
|
() => () => {
|
|
12263
|
-
dragStateRef.current
|
|
12477
|
+
const dragState = dragStateRef.current;
|
|
12478
|
+
dragState?.stopTracking();
|
|
12479
|
+
dragState?.releaseInteractionLock();
|
|
12264
12480
|
dragStateRef.current = null;
|
|
12265
12481
|
},
|
|
12266
12482
|
[]
|
|
@@ -12317,6 +12533,7 @@ function HotspotAnchor({
|
|
|
12317
12533
|
if (!dragState) {
|
|
12318
12534
|
return;
|
|
12319
12535
|
}
|
|
12536
|
+
dragState.stopTracking();
|
|
12320
12537
|
dragState.releaseInteractionLock();
|
|
12321
12538
|
dragStateRef.current = null;
|
|
12322
12539
|
setDragging(false);
|
|
@@ -12339,6 +12556,7 @@ function HotspotAnchor({
|
|
|
12339
12556
|
worldHeight,
|
|
12340
12557
|
resolvedDistance
|
|
12341
12558
|
);
|
|
12559
|
+
placeSelectionFrame(selectionFrameRef.current, group, camera, size.height);
|
|
12342
12560
|
if (tooltipOpen && tooltipAnchorRef.current) {
|
|
12343
12561
|
updateTooltipAnchor(
|
|
12344
12562
|
tooltipAnchorRef.current,
|
|
@@ -12357,6 +12575,7 @@ function HotspotAnchor({
|
|
|
12357
12575
|
rotation,
|
|
12358
12576
|
scaleMode,
|
|
12359
12577
|
size,
|
|
12578
|
+
selected,
|
|
12360
12579
|
surfaceQuaternion3,
|
|
12361
12580
|
tooltipOpen,
|
|
12362
12581
|
tooltipPlacement,
|
|
@@ -12382,6 +12601,12 @@ function HotspotAnchor({
|
|
|
12382
12601
|
worldHeight,
|
|
12383
12602
|
resolvedDistance
|
|
12384
12603
|
);
|
|
12604
|
+
placeSelectionFrame(
|
|
12605
|
+
selectionFrameRef.current,
|
|
12606
|
+
group,
|
|
12607
|
+
state.camera,
|
|
12608
|
+
state.size.height
|
|
12609
|
+
);
|
|
12385
12610
|
if (tooltipOpen && tooltipAnchorRef.current) {
|
|
12386
12611
|
updateTooltipAnchor(
|
|
12387
12612
|
tooltipAnchorRef.current,
|
|
@@ -12397,31 +12622,78 @@ function HotspotAnchor({
|
|
|
12397
12622
|
event.stopPropagation();
|
|
12398
12623
|
event.nativeEvent.stopImmediatePropagation?.();
|
|
12399
12624
|
};
|
|
12400
|
-
const
|
|
12625
|
+
const dragPosition = (dragState, event) => {
|
|
12626
|
+
const pointerPosition = pointerToPanoPosition(event, gl.domElement, camera);
|
|
12627
|
+
if (!pointerPosition) {
|
|
12628
|
+
return dragState.lastPosition;
|
|
12629
|
+
}
|
|
12630
|
+
return translateHotspotPosition(
|
|
12631
|
+
dragState.startPosition,
|
|
12632
|
+
dragState.pointerOrigin,
|
|
12633
|
+
pointerPosition
|
|
12634
|
+
);
|
|
12635
|
+
};
|
|
12636
|
+
updateDragRef.current = (nativeEvent) => {
|
|
12401
12637
|
const dragState = dragStateRef.current;
|
|
12402
|
-
if (!dragState || dragState.pointerId !==
|
|
12638
|
+
if (!dragState || dragState.pointerId !== nativeEvent.pointerId) {
|
|
12403
12639
|
return;
|
|
12404
12640
|
}
|
|
12405
|
-
|
|
12406
|
-
|
|
12407
|
-
|
|
12408
|
-
|
|
12409
|
-
|
|
12410
|
-
|
|
12411
|
-
|
|
12412
|
-
|
|
12413
|
-
|
|
12414
|
-
|
|
12415
|
-
|
|
12416
|
-
|
|
12641
|
+
const nextPosition = dragPosition(dragState, nativeEvent);
|
|
12642
|
+
dragState.lastPosition = nextPosition;
|
|
12643
|
+
dragState.moved || (dragState.moved = angularDistance(dragState.startPosition, nextPosition) > DRAG_EPSILON_DEGREES);
|
|
12644
|
+
onPositionChange?.({
|
|
12645
|
+
id,
|
|
12646
|
+
position: nextPosition,
|
|
12647
|
+
source: "pointer",
|
|
12648
|
+
nativeEvent,
|
|
12649
|
+
startPosition: dragState.startPosition
|
|
12650
|
+
});
|
|
12651
|
+
};
|
|
12652
|
+
endDragRef.current = (nativeEvent, emitDragEnd) => {
|
|
12653
|
+
const dragState = dragStateRef.current;
|
|
12654
|
+
if (!dragState || dragState.pointerId !== nativeEvent.pointerId) {
|
|
12655
|
+
return;
|
|
12417
12656
|
}
|
|
12418
|
-
|
|
12657
|
+
const nextPosition = dragPosition(dragState, nativeEvent);
|
|
12658
|
+
dragState.lastPosition = nextPosition;
|
|
12659
|
+
dragState.moved || (dragState.moved = angularDistance(dragState.startPosition, nextPosition) > DRAG_EPSILON_DEGREES);
|
|
12660
|
+
const moved = dragState.moved;
|
|
12661
|
+
const startPosition = dragState.startPosition;
|
|
12662
|
+
dragState.stopTracking();
|
|
12419
12663
|
dragState.releaseInteractionLock();
|
|
12420
12664
|
dragStateRef.current = null;
|
|
12665
|
+
suppressNextClickRef.current = moved;
|
|
12421
12666
|
setDragging(false);
|
|
12422
|
-
if (emitDragEnd) {
|
|
12423
|
-
|
|
12667
|
+
if (!emitDragEnd) {
|
|
12668
|
+
return;
|
|
12424
12669
|
}
|
|
12670
|
+
const overHotspot = pointerHitsHotspot(
|
|
12671
|
+
nativeEvent,
|
|
12672
|
+
gl.domElement,
|
|
12673
|
+
camera,
|
|
12674
|
+
groupRef.current
|
|
12675
|
+
);
|
|
12676
|
+
eventHovered.current = overHotspot;
|
|
12677
|
+
setHovered(overHotspot);
|
|
12678
|
+
if (moved && typeof window !== "undefined") {
|
|
12679
|
+
suppressFollowingClick(window);
|
|
12680
|
+
}
|
|
12681
|
+
if (moved) {
|
|
12682
|
+
onPositionChange?.({
|
|
12683
|
+
id,
|
|
12684
|
+
position: nextPosition,
|
|
12685
|
+
source: "pointer",
|
|
12686
|
+
nativeEvent,
|
|
12687
|
+
startPosition
|
|
12688
|
+
});
|
|
12689
|
+
}
|
|
12690
|
+
onDragEnd?.({
|
|
12691
|
+
id,
|
|
12692
|
+
position: nextPosition,
|
|
12693
|
+
source: "pointer",
|
|
12694
|
+
nativeEvent,
|
|
12695
|
+
startPosition
|
|
12696
|
+
});
|
|
12425
12697
|
};
|
|
12426
12698
|
return /* @__PURE__ */ jsxs15(
|
|
12427
12699
|
"group",
|
|
@@ -12441,23 +12713,42 @@ function HotspotAnchor({
|
|
|
12441
12713
|
}
|
|
12442
12714
|
suppressNextClickRef.current = false;
|
|
12443
12715
|
} : void 0,
|
|
12444
|
-
onLostPointerCapture: acceptsPointer ? (event) =>
|
|
12445
|
-
|
|
12716
|
+
onLostPointerCapture: acceptsPointer ? (event) => {
|
|
12717
|
+
endDragRef.current(event.nativeEvent, true);
|
|
12718
|
+
} : void 0,
|
|
12719
|
+
onPointerCancel: acceptsPointer ? (event) => {
|
|
12720
|
+
endDragRef.current(event.nativeEvent, true);
|
|
12721
|
+
} : void 0,
|
|
12446
12722
|
onPointerDown: acceptsPointer ? (event) => {
|
|
12447
|
-
|
|
12723
|
+
const native = event.nativeEvent;
|
|
12448
12724
|
if (!draggable || dragStateRef.current) {
|
|
12725
|
+
stopPointerEvent(event);
|
|
12449
12726
|
return;
|
|
12450
12727
|
}
|
|
12728
|
+
const pointerId = native.pointerId;
|
|
12729
|
+
stopPointerEvent(event);
|
|
12451
12730
|
const releaseInteractionLock = controlsRef?.current?.acquireInteractionLock() ?? (() => void 0);
|
|
12452
|
-
const
|
|
12453
|
-
target.setPointerCapture?.(event.pointerId);
|
|
12731
|
+
const pointerOrigin = pointerToPanoPosition(native, gl.domElement, camera) ?? vector3ToPanoPosition(event.ray.direction);
|
|
12454
12732
|
const startPosition = { ...normalizedPosition };
|
|
12733
|
+
const tracksOutsideMesh = typeof window !== "undefined";
|
|
12734
|
+
const stopTracking = tracksOutsideMesh ? trackPointerDrag(
|
|
12735
|
+
window,
|
|
12736
|
+
gl.domElement,
|
|
12737
|
+
pointerId,
|
|
12738
|
+
(pointerEvent) => updateDragRef.current(pointerEvent),
|
|
12739
|
+
(pointerEvent) => endDragRef.current(pointerEvent, true)
|
|
12740
|
+
) : () => void 0;
|
|
12455
12741
|
dragStateRef.current = {
|
|
12456
|
-
pointerId
|
|
12742
|
+
pointerId,
|
|
12457
12743
|
startPosition,
|
|
12744
|
+
pointerOrigin,
|
|
12745
|
+
lastPosition: startPosition,
|
|
12458
12746
|
releaseInteractionLock,
|
|
12459
|
-
moved: false
|
|
12747
|
+
moved: false,
|
|
12748
|
+
tracksOutsideMesh,
|
|
12749
|
+
stopTracking
|
|
12460
12750
|
};
|
|
12751
|
+
eventHovered.current = false;
|
|
12461
12752
|
setHovered(false);
|
|
12462
12753
|
setDragging(true);
|
|
12463
12754
|
onDragStart?.({
|
|
@@ -12468,17 +12759,13 @@ function HotspotAnchor({
|
|
|
12468
12759
|
} : void 0,
|
|
12469
12760
|
onPointerMove: acceptsPointer ? (event) => {
|
|
12470
12761
|
const dragState = dragStateRef.current;
|
|
12471
|
-
if (!dragState || dragState.pointerId !== event.pointerId) {
|
|
12762
|
+
if (!dragState || dragState.pointerId !== event.nativeEvent.pointerId) {
|
|
12472
12763
|
return;
|
|
12473
12764
|
}
|
|
12474
12765
|
stopPointerEvent(event);
|
|
12475
|
-
|
|
12476
|
-
|
|
12477
|
-
|
|
12478
|
-
...makeInteractionEvent(id, nextPosition, event),
|
|
12479
|
-
source: "pointer",
|
|
12480
|
-
startPosition: dragState.startPosition
|
|
12481
|
-
});
|
|
12766
|
+
if (!dragState.tracksOutsideMesh) {
|
|
12767
|
+
updateDragRef.current(event.nativeEvent);
|
|
12768
|
+
}
|
|
12482
12769
|
} : void 0,
|
|
12483
12770
|
onPointerOut: acceptsPointer ? (event) => {
|
|
12484
12771
|
if (!dragStateRef.current) {
|
|
@@ -12507,7 +12794,10 @@ function HotspotAnchor({
|
|
|
12507
12794
|
);
|
|
12508
12795
|
}
|
|
12509
12796
|
} : void 0,
|
|
12510
|
-
onPointerUp: acceptsPointer ? (event) =>
|
|
12797
|
+
onPointerUp: acceptsPointer ? (event) => {
|
|
12798
|
+
stopPointerEvent(event);
|
|
12799
|
+
endDragRef.current(event.nativeEvent, true);
|
|
12800
|
+
} : void 0,
|
|
12511
12801
|
children: [
|
|
12512
12802
|
focused ? focusContent ?? /* @__PURE__ */ jsx26(
|
|
12513
12803
|
"lineSegments",
|
|
@@ -12520,16 +12810,16 @@ function HotspotAnchor({
|
|
|
12520
12810
|
}
|
|
12521
12811
|
) : null,
|
|
12522
12812
|
children,
|
|
12523
|
-
selected && useAngularScale ? /* @__PURE__ */ jsx26(
|
|
12813
|
+
selected && useAngularScale ? /* @__PURE__ */ jsx26("group", { ref: selectionFrameRef, children: /* @__PURE__ */ jsx26(
|
|
12524
12814
|
HotspotStrokeLine,
|
|
12525
12815
|
{
|
|
12526
12816
|
points: SELECTION_BORDER_POINTS,
|
|
12527
12817
|
color: "#ffb300",
|
|
12528
|
-
lineWidth:
|
|
12818
|
+
lineWidth: SELECTION_BORDER_WIDTH,
|
|
12529
12819
|
opacity: 1,
|
|
12530
12820
|
renderOrder: renderOrder + 1
|
|
12531
12821
|
}
|
|
12532
|
-
) : null,
|
|
12822
|
+
) }) : null,
|
|
12533
12823
|
tooltipOpen && tooltipContent ? /* @__PURE__ */ jsx26("group", { ref: tooltipAnchorRef, children: /* @__PURE__ */ jsx26(
|
|
12534
12824
|
HotspotTooltip,
|
|
12535
12825
|
{
|
|
@@ -12549,11 +12839,11 @@ import {
|
|
|
12549
12839
|
DoubleSide as DoubleSide3,
|
|
12550
12840
|
Mesh as Mesh4,
|
|
12551
12841
|
MeshBasicMaterial,
|
|
12552
|
-
Vector2 as
|
|
12842
|
+
Vector2 as Vector25
|
|
12553
12843
|
} from "three";
|
|
12554
12844
|
import { jsx as jsx27, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
12555
12845
|
var HOTSPOT_ALPHA_CUTOFF = 0.05;
|
|
12556
|
-
var SAMPLE_UV = new
|
|
12846
|
+
var SAMPLE_UV = new Vector25();
|
|
12557
12847
|
var RAYCAST_HITS = [];
|
|
12558
12848
|
var IMAGE_DATA_CACHE = /* @__PURE__ */ new WeakMap();
|
|
12559
12849
|
function clampOpacity(opacity) {
|
|
@@ -13816,7 +14106,7 @@ import {
|
|
|
13816
14106
|
ClampToEdgeWrapping as ClampToEdgeWrapping8,
|
|
13817
14107
|
LinearFilter as LinearFilter10,
|
|
13818
14108
|
MathUtils as MathUtils10,
|
|
13819
|
-
PerspectiveCamera as
|
|
14109
|
+
PerspectiveCamera as PerspectiveCamera9,
|
|
13820
14110
|
SRGBColorSpace as SRGBColorSpace9
|
|
13821
14111
|
} from "three";
|
|
13822
14112
|
import { jsx as jsx33 } from "react/jsx-runtime";
|
|
@@ -14070,11 +14360,15 @@ function createTextTexture(text, width, height, style, rasterLong) {
|
|
|
14070
14360
|
if (!context) {
|
|
14071
14361
|
throw new Error("Canvas 2D is unavailable for this text hotspot.");
|
|
14072
14362
|
}
|
|
14073
|
-
|
|
14074
|
-
|
|
14075
|
-
|
|
14076
|
-
|
|
14077
|
-
|
|
14363
|
+
context.setTransform(
|
|
14364
|
+
canvasWidth / layout.canvasWidth,
|
|
14365
|
+
0,
|
|
14366
|
+
0,
|
|
14367
|
+
canvasHeight / layout.canvasHeight,
|
|
14368
|
+
0,
|
|
14369
|
+
0
|
|
14370
|
+
);
|
|
14371
|
+
drawTextHotspot(context, layout.canvasWidth, layout.canvasHeight, text, style);
|
|
14078
14372
|
const texture = new CanvasTexture3(canvas);
|
|
14079
14373
|
texture.colorSpace = SRGBColorSpace9;
|
|
14080
14374
|
texture.wrapS = ClampToEdgeWrapping8;
|
|
@@ -14092,7 +14386,7 @@ function useRasterLongSide(width, height, scale, scaleMode, referenceFov) {
|
|
|
14092
14386
|
const measure = () => {
|
|
14093
14387
|
const pixelRatio = getPixelRatio();
|
|
14094
14388
|
const viewportHeight = size.height * (Number.isFinite(pixelRatio) && pixelRatio > 0 ? pixelRatio : 1);
|
|
14095
|
-
const cameraFov = camera instanceof
|
|
14389
|
+
const cameraFov = camera instanceof PerspectiveCamera9 ? camera.fov : DEFAULT_REFERENCE_FOV2;
|
|
14096
14390
|
const screenLong = Math.max(
|
|
14097
14391
|
projectedDevicePixels(
|
|
14098
14392
|
width * resolveScale2(scale),
|
|
@@ -14134,13 +14428,7 @@ function useTextTexture(text, width, height, style, scale, scaleMode, referenceF
|
|
|
14134
14428
|
let nextTexture = null;
|
|
14135
14429
|
const run = async () => {
|
|
14136
14430
|
try {
|
|
14137
|
-
const
|
|
14138
|
-
const layoutLong = Math.max(layout.canvasWidth, layout.canvasHeight);
|
|
14139
|
-
const drawScale = rasterLong / layoutLong;
|
|
14140
|
-
const { font } = resolveTextFont({
|
|
14141
|
-
...style,
|
|
14142
|
-
fontSize: resolvePositive(style.fontSize, DEFAULT_FONT_SIZE) * drawScale
|
|
14143
|
-
});
|
|
14431
|
+
const { font } = resolveTextFont(style);
|
|
14144
14432
|
try {
|
|
14145
14433
|
await document.fonts?.load(font);
|
|
14146
14434
|
} catch {
|
|
@@ -14369,7 +14657,7 @@ import {
|
|
|
14369
14657
|
Matrix4 as Matrix45,
|
|
14370
14658
|
Quaternion as Quaternion4,
|
|
14371
14659
|
ShapeUtils,
|
|
14372
|
-
Vector2 as
|
|
14660
|
+
Vector2 as Vector26,
|
|
14373
14661
|
Vector3 as Vector318
|
|
14374
14662
|
} from "three";
|
|
14375
14663
|
import { jsx as jsx35, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
@@ -14407,7 +14695,7 @@ function intersects(a, b, c, d) {
|
|
|
14407
14695
|
}
|
|
14408
14696
|
function hasSelfIntersection(vertices) {
|
|
14409
14697
|
const points = vertices.map(
|
|
14410
|
-
(vertex) => new
|
|
14698
|
+
(vertex) => new Vector26(vertex.unwrappedYaw, vertex.pitch)
|
|
14411
14699
|
);
|
|
14412
14700
|
for (let index = 0; index < points.length; index += 1) {
|
|
14413
14701
|
const nextIndex = (index + 1) % points.length;
|
|
@@ -14556,7 +14844,7 @@ function addSubdividedTriangle(positions, indices, a, b, c, worldToLocal, steps)
|
|
|
14556
14844
|
}
|
|
14557
14845
|
function makeFillGeometry(vertices, center) {
|
|
14558
14846
|
const unwrapped = unwrapPolygonVertices(vertices);
|
|
14559
|
-
const contour = unwrapped.map((vertex) => new
|
|
14847
|
+
const contour = unwrapped.map((vertex) => new Vector26(vertex.unwrappedYaw, vertex.pitch));
|
|
14560
14848
|
const triangles = ShapeUtils.triangulateShape(contour, []);
|
|
14561
14849
|
const positions = [];
|
|
14562
14850
|
const indices = [];
|
|
@@ -16054,12 +16342,12 @@ import { useFrame as useFrame21, useThree as useThree26 } from "@react-three/fib
|
|
|
16054
16342
|
import { useRef as useRef36 } from "react";
|
|
16055
16343
|
import {
|
|
16056
16344
|
DoubleSide as DoubleSide6,
|
|
16057
|
-
Raycaster as
|
|
16058
|
-
Vector2 as
|
|
16345
|
+
Raycaster as Raycaster4,
|
|
16346
|
+
Vector2 as Vector27,
|
|
16059
16347
|
Vector3 as Vector321
|
|
16060
16348
|
} from "three";
|
|
16061
16349
|
import { jsx as jsx38, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
16062
|
-
var CENTER_NDC = new
|
|
16350
|
+
var CENTER_NDC = new Vector27(0, 0);
|
|
16063
16351
|
var HUD_DISTANCE = 2;
|
|
16064
16352
|
var RETICLE_SCALE = 1;
|
|
16065
16353
|
var RETICLE_RENDER_ORDER = 1e5;
|
|
@@ -16145,7 +16433,7 @@ function WebVRReticle({
|
|
|
16145
16433
|
const groupRef = useRef36(null);
|
|
16146
16434
|
const ringMeshRef = useRef36(null);
|
|
16147
16435
|
const directionRef = useRef36(new Vector321());
|
|
16148
|
-
const raycasterRef = useRef36(new
|
|
16436
|
+
const raycasterRef = useRef36(new Raycaster4());
|
|
16149
16437
|
const hoveredRef = useRef36(null);
|
|
16150
16438
|
const dwellRef = useRef36(0);
|
|
16151
16439
|
const clickedRef = useRef36(false);
|
|
@@ -16315,12 +16603,12 @@ import { useContext as useContext26, useEffect as useEffect36, useMemo as useMem
|
|
|
16315
16603
|
import {
|
|
16316
16604
|
Mesh as Mesh6,
|
|
16317
16605
|
OrthographicCamera,
|
|
16318
|
-
PerspectiveCamera as
|
|
16606
|
+
PerspectiveCamera as PerspectiveCamera10,
|
|
16319
16607
|
PlaneGeometry as PlaneGeometry5,
|
|
16320
16608
|
Scene,
|
|
16321
16609
|
ShaderMaterial as ShaderMaterial3,
|
|
16322
16610
|
StereoCamera as StereoCamera2,
|
|
16323
|
-
Vector2 as
|
|
16611
|
+
Vector2 as Vector28,
|
|
16324
16612
|
Vector4 as Vector42,
|
|
16325
16613
|
WebGLRenderTarget as WebGLRenderTarget2
|
|
16326
16614
|
} from "three";
|
|
@@ -16358,7 +16646,7 @@ function createDistortionResources() {
|
|
|
16358
16646
|
depthWrite: false,
|
|
16359
16647
|
fragmentShader,
|
|
16360
16648
|
uniforms: {
|
|
16361
|
-
distortion: { value: new
|
|
16649
|
+
distortion: { value: new Vector28() },
|
|
16362
16650
|
sourceTexture: { value: target.texture }
|
|
16363
16651
|
},
|
|
16364
16652
|
vertexShader
|
|
@@ -16406,7 +16694,7 @@ function WebVRStereoRenderer({
|
|
|
16406
16694
|
const stereoRef = useRef37(stereo);
|
|
16407
16695
|
stereoRef.current = stereo;
|
|
16408
16696
|
const resources = useMemo25(createDistortionResources, []);
|
|
16409
|
-
const drawingSizeRef = useRef37(new
|
|
16697
|
+
const drawingSizeRef = useRef37(new Vector28());
|
|
16410
16698
|
const viewportRef = useRef37(new Vector42());
|
|
16411
16699
|
const scissorRef = useRef37(new Vector42());
|
|
16412
16700
|
const originalFovRef = useRef37(null);
|
|
@@ -16426,7 +16714,7 @@ function WebVRStereoRenderer({
|
|
|
16426
16714
|
useEffect36(() => {
|
|
16427
16715
|
const originalRender = gl.render.bind(gl);
|
|
16428
16716
|
gl.render = (sceneToRender, cameraToRender) => {
|
|
16429
|
-
if (!stereoActiveRef.current || !(cameraToRender instanceof
|
|
16717
|
+
if (!stereoActiveRef.current || !(cameraToRender instanceof PerspectiveCamera10)) {
|
|
16430
16718
|
originalRender(sceneToRender, cameraToRender);
|
|
16431
16719
|
return;
|
|
16432
16720
|
}
|
|
@@ -16501,7 +16789,7 @@ function WebVRStereoRenderer({
|
|
|
16501
16789
|
if (runtime) {
|
|
16502
16790
|
runtime.stereoView.active = fallback;
|
|
16503
16791
|
}
|
|
16504
|
-
if (fallback && camera instanceof
|
|
16792
|
+
if (fallback && camera instanceof PerspectiveCamera10) {
|
|
16505
16793
|
syncStereoCameras(
|
|
16506
16794
|
stereoRef.current,
|
|
16507
16795
|
camera,
|
|
@@ -16512,7 +16800,7 @@ function WebVRStereoRenderer({
|
|
|
16512
16800
|
);
|
|
16513
16801
|
return;
|
|
16514
16802
|
}
|
|
16515
|
-
if (originalFovRef.current !== null && camera instanceof
|
|
16803
|
+
if (originalFovRef.current !== null && camera instanceof PerspectiveCamera10) {
|
|
16516
16804
|
camera.fov = originalFovRef.current;
|
|
16517
16805
|
camera.updateProjectionMatrix();
|
|
16518
16806
|
originalFovRef.current = null;
|