@babylonjs/addons 7.32.4 → 7.34.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/htmlMesh/fitStrategy.d.ts +10 -0
- package/htmlMesh/fitStrategy.js +84 -0
- package/htmlMesh/fitStrategy.js.map +1 -0
- package/htmlMesh/htmlMesh.d.ts +114 -0
- package/htmlMesh/htmlMesh.js +301 -0
- package/htmlMesh/htmlMesh.js.map +1 -0
- package/htmlMesh/htmlMeshRenderer.d.ts +72 -0
- package/htmlMesh/htmlMeshRenderer.js +464 -0
- package/htmlMesh/htmlMeshRenderer.js.map +1 -0
- package/htmlMesh/index.d.ts +5 -0
- package/htmlMesh/index.js +7 -0
- package/htmlMesh/index.js.map +1 -0
- package/htmlMesh/pointerEventsCapture.d.ts +37 -0
- package/htmlMesh/pointerEventsCapture.js +152 -0
- package/htmlMesh/pointerEventsCapture.js.map +1 -0
- package/htmlMesh/pointerEventsCaptureBehavior.d.ts +47 -0
- package/htmlMesh/pointerEventsCaptureBehavior.js +191 -0
- package/htmlMesh/pointerEventsCaptureBehavior.js.map +1 -0
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { Tools } from "@babylonjs/core/Misc/tools.js";
|
|
2
|
+
let captureRequestQueue = [];
|
|
3
|
+
// Key is request id, value is object with capture and release callbacks
|
|
4
|
+
const pendingRequestCallbacks = new Map();
|
|
5
|
+
// Keep track of release requests with no matching capture request
|
|
6
|
+
// in case the release request arrived before the capture to avoid
|
|
7
|
+
// the capture request never getting released.
|
|
8
|
+
let unmatchedReleaseRequests = [];
|
|
9
|
+
let currentOwner = null; // Called on first capture or release request
|
|
10
|
+
/**
|
|
11
|
+
* Get the id of the object currently capturing pointer events
|
|
12
|
+
* @returns The id of the object currently capturing pointer events
|
|
13
|
+
* or null if no object is capturing pointer events
|
|
14
|
+
*/
|
|
15
|
+
export const getCapturingId = () => {
|
|
16
|
+
return currentOwner;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Request that the object with the given id capture pointer events. If there is no current
|
|
20
|
+
* owner, then the request is granted immediately. If there is a current owner, then the request
|
|
21
|
+
* is queued until the current owner releases pointer events.
|
|
22
|
+
* @param requestId An id to identify the request. This id will be used to match the capture
|
|
23
|
+
* request with the release request.
|
|
24
|
+
* @param captureCallback The callback to call when the request is granted and the object is capturing
|
|
25
|
+
* @param releaseCallback The callback to call when the object is no longer capturing pointer events
|
|
26
|
+
*/
|
|
27
|
+
export const requestCapture = (requestId, captureCallback, releaseCallback) => {
|
|
28
|
+
debugLog(`In pointerEventsCapture.requestCapture - Pointer events capture requested for ${requestId}`);
|
|
29
|
+
// If there is a release for this request, then ignore the request
|
|
30
|
+
if (removeUnmatchedRequest(requestId)) {
|
|
31
|
+
debugLog(`In pointerEventsCapture.requestCapture - Capture request matched previous release request ${requestId}. Cancelling capture request`);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
else if (requestId !== currentOwner) {
|
|
35
|
+
// if the request is not already in the queue, add it to the queue
|
|
36
|
+
enqueueCaptureRequest(requestId, captureCallback, releaseCallback);
|
|
37
|
+
}
|
|
38
|
+
if (!currentOwner) {
|
|
39
|
+
// If there is no current owner, go ahead and grant the request
|
|
40
|
+
transferPointerEventsOwnership();
|
|
41
|
+
}
|
|
42
|
+
// If the request id is the current owner, do nothing
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Release pointer events from the object with the given id. If the object is the current owner
|
|
46
|
+
* then pointer events are released immediately. If the object is not the current owner, then the
|
|
47
|
+
* associated capture request is removed from the queue. If there is no matching capture request
|
|
48
|
+
* in the queue, then the release request is added to a list of unmatched release requests and will
|
|
49
|
+
* negate the next capture request with the same id. This is to guard against the possibility that
|
|
50
|
+
* the release request arrived before the capture request.
|
|
51
|
+
* @param requestId The id which should match the id of the capture request
|
|
52
|
+
*/
|
|
53
|
+
export const requestRelease = (requestId) => {
|
|
54
|
+
debugLog(`In pointerEventsCapture.requestRelease - Pointer events release requested for ${requestId}`);
|
|
55
|
+
// if the requestId is the current capture holder release it
|
|
56
|
+
if (!requestId || requestId === currentOwner) {
|
|
57
|
+
transferPointerEventsOwnership();
|
|
58
|
+
}
|
|
59
|
+
else if (cancelRequest(requestId)) {
|
|
60
|
+
// if the request is in the queue, but not the current capture holder, remove it and it's callbacks
|
|
61
|
+
pendingRequestCallbacks.delete(requestId);
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
debugLog(`In pointerEventsCapture.requestRelease - Received release request ${requestId} but no matching capture request was received`);
|
|
65
|
+
// request was not current and not in queue, likely because we received a release
|
|
66
|
+
// request before the capture. Add it to the unmatched list to guard against this possibility
|
|
67
|
+
if (!unmatchedReleaseRequests.includes(requestId)) {
|
|
68
|
+
unmatchedReleaseRequests.push(requestId);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Relase pointer events from the current owner
|
|
74
|
+
*/
|
|
75
|
+
export const releaseCurrent = () => {
|
|
76
|
+
requestRelease(currentOwner);
|
|
77
|
+
};
|
|
78
|
+
const enqueueCaptureRequest = (requestId, capture, release) => {
|
|
79
|
+
debugLog(`In pointerEventsCapture.enqueueCaptureRequest - Enqueueing capture request for ${requestId}`);
|
|
80
|
+
if (!captureRequestQueue.includes(requestId)) {
|
|
81
|
+
captureRequestQueue.push(requestId);
|
|
82
|
+
pendingRequestCallbacks.set(requestId, { capture, release });
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
// Removes the request from the queue if it exists. Returns true
|
|
86
|
+
// if the request was found and removed, otherwise false
|
|
87
|
+
const cancelRequest = (requestId) => {
|
|
88
|
+
let removed = false;
|
|
89
|
+
captureRequestQueue = captureRequestQueue.filter((id) => {
|
|
90
|
+
if (id !== requestId) {
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
removed = true;
|
|
95
|
+
debugLog(`In pointerEventsCapture.cancelRequest - Canceling pointer events capture request ${requestId}`);
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
return removed;
|
|
100
|
+
};
|
|
101
|
+
const removeUnmatchedRequest = (requestId) => {
|
|
102
|
+
let removed = false;
|
|
103
|
+
unmatchedReleaseRequests = unmatchedReleaseRequests.filter((id) => {
|
|
104
|
+
if (id !== requestId) {
|
|
105
|
+
return true;
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
removed = true;
|
|
109
|
+
return false;
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
return removed;
|
|
113
|
+
};
|
|
114
|
+
const transferPointerEventsOwnership = () => {
|
|
115
|
+
const newOwnerId = nextCaptureRequest();
|
|
116
|
+
debugLog(`In pointerEventsCapture.transferPointerEventsOwnership - Transferrring pointer events from ${currentOwner} to ${newOwnerId}`);
|
|
117
|
+
// Release the current owner
|
|
118
|
+
doRelease();
|
|
119
|
+
if (newOwnerId) {
|
|
120
|
+
doCapture(newOwnerId);
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
const doRelease = () => {
|
|
124
|
+
debugLog(`In pointerEventsCapture.doRelease - Releasing pointer events from ${currentOwner}`);
|
|
125
|
+
if (currentOwner) {
|
|
126
|
+
// call the release callback
|
|
127
|
+
pendingRequestCallbacks.get(currentOwner)?.release();
|
|
128
|
+
// And remove the callbacks
|
|
129
|
+
pendingRequestCallbacks.delete(currentOwner);
|
|
130
|
+
currentOwner = null;
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
const doCapture = (newOwnerId) => {
|
|
134
|
+
if (newOwnerId) {
|
|
135
|
+
// call the capture callback
|
|
136
|
+
pendingRequestCallbacks.get(newOwnerId)?.capture();
|
|
137
|
+
}
|
|
138
|
+
currentOwner = newOwnerId;
|
|
139
|
+
debugLog(`In pointerEventsCapture.doCapture - Pointer events now captured by ${newOwnerId}`);
|
|
140
|
+
};
|
|
141
|
+
const nextCaptureRequest = () => {
|
|
142
|
+
return captureRequestQueue.length > 0 ? captureRequestQueue.shift() : null;
|
|
143
|
+
};
|
|
144
|
+
const debugLog = (message) => {
|
|
145
|
+
// If we are runnning in a test runner (in node, so window is not defined)
|
|
146
|
+
// or if the debug flag is set, then log the message
|
|
147
|
+
if (typeof window === "undefined" || window["pointer-events-capture-debug"]) {
|
|
148
|
+
Tools.Log(`${performance.now()} - game.scene.pointerEvents - ${message}\ncurrentOwner: ${currentOwner}\nqueue: ${captureRequestQueue}\nunmatched: ${unmatchedReleaseRequests}`);
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
// #endregion Debugging support
|
|
152
|
+
//# sourceMappingURL=pointerEventsCapture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pointerEventsCapture.js","sourceRoot":"","sources":["../../../../dev/addons/src/htmlMesh/pointerEventsCapture.ts"],"names":[],"mappings":"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","sourcesContent":["import { Tools } from \"core/Misc/tools\";\r\n\r\n// A capture management system to ensure that the correct object has the pointer\r\n// events by eliminating race conditions that can cause the pointer events to be\r\n// released by a different object after they are captured leaving no object\r\n// as the owner. It does this by queueing requests and only allowing\r\n// capture when the current capture owner releases pointer events.\r\n\r\ntype CaptureReleaseCallback = () => void;\r\n\r\ntype CaptureReleaseCallbacks = {\r\n capture: CaptureReleaseCallback;\r\n release: CaptureReleaseCallback;\r\n};\r\n\r\nlet captureRequestQueue: string[] = [];\r\n\r\n// Key is request id, value is object with capture and release callbacks\r\nconst pendingRequestCallbacks: Map<string, CaptureReleaseCallbacks> = new Map();\r\n\r\n// Keep track of release requests with no matching capture request\r\n// in case the release request arrived before the capture to avoid\r\n// the capture request never getting released.\r\nlet unmatchedReleaseRequests: string[] = [];\r\n\r\nlet currentOwner: string | null = null; // Called on first capture or release request\r\n\r\n/**\r\n * Get the id of the object currently capturing pointer events\r\n * @returns The id of the object currently capturing pointer events\r\n * or null if no object is capturing pointer events\r\n */\r\nexport const getCapturingId = () => {\r\n return currentOwner;\r\n};\r\n\r\n/**\r\n * Request that the object with the given id capture pointer events. If there is no current\r\n * owner, then the request is granted immediately. If there is a current owner, then the request\r\n * is queued until the current owner releases pointer events.\r\n * @param requestId An id to identify the request. This id will be used to match the capture\r\n * request with the release request.\r\n * @param captureCallback The callback to call when the request is granted and the object is capturing\r\n * @param releaseCallback The callback to call when the object is no longer capturing pointer events\r\n */\r\nexport const requestCapture = (requestId: string, captureCallback: CaptureReleaseCallback, releaseCallback: CaptureReleaseCallback) => {\r\n debugLog(`In pointerEventsCapture.requestCapture - Pointer events capture requested for ${requestId}`);\r\n\r\n // If there is a release for this request, then ignore the request\r\n if (removeUnmatchedRequest(requestId)) {\r\n debugLog(`In pointerEventsCapture.requestCapture - Capture request matched previous release request ${requestId}. Cancelling capture request`);\r\n return;\r\n } else if (requestId !== currentOwner) {\r\n // if the request is not already in the queue, add it to the queue\r\n enqueueCaptureRequest(requestId, captureCallback, releaseCallback);\r\n }\r\n\r\n if (!currentOwner) {\r\n // If there is no current owner, go ahead and grant the request\r\n transferPointerEventsOwnership();\r\n }\r\n // If the request id is the current owner, do nothing\r\n};\r\n\r\n/**\r\n * Release pointer events from the object with the given id. If the object is the current owner\r\n * then pointer events are released immediately. If the object is not the current owner, then the\r\n * associated capture request is removed from the queue. If there is no matching capture request\r\n * in the queue, then the release request is added to a list of unmatched release requests and will\r\n * negate the next capture request with the same id. This is to guard against the possibility that\r\n * the release request arrived before the capture request.\r\n * @param requestId The id which should match the id of the capture request\r\n */\r\nexport const requestRelease = (requestId: string | null) => {\r\n debugLog(`In pointerEventsCapture.requestRelease - Pointer events release requested for ${requestId}`);\r\n\r\n // if the requestId is the current capture holder release it\r\n if (!requestId || requestId === currentOwner) {\r\n transferPointerEventsOwnership();\r\n } else if (cancelRequest(requestId)) {\r\n // if the request is in the queue, but not the current capture holder, remove it and it's callbacks\r\n pendingRequestCallbacks.delete(requestId);\r\n } else {\r\n debugLog(`In pointerEventsCapture.requestRelease - Received release request ${requestId} but no matching capture request was received`);\r\n // request was not current and not in queue, likely because we received a release\r\n // request before the capture. Add it to the unmatched list to guard against this possibility\r\n if (!unmatchedReleaseRequests.includes(requestId)) {\r\n unmatchedReleaseRequests.push(requestId);\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Relase pointer events from the current owner\r\n */\r\nexport const releaseCurrent = () => {\r\n requestRelease(currentOwner);\r\n};\r\n\r\nconst enqueueCaptureRequest = (requestId: string, capture: CaptureReleaseCallback, release: CaptureReleaseCallback) => {\r\n debugLog(`In pointerEventsCapture.enqueueCaptureRequest - Enqueueing capture request for ${requestId}`);\r\n if (!captureRequestQueue.includes(requestId)) {\r\n captureRequestQueue.push(requestId);\r\n pendingRequestCallbacks.set(requestId, { capture, release });\r\n }\r\n};\r\n\r\n// Removes the request from the queue if it exists. Returns true\r\n// if the request was found and removed, otherwise false\r\nconst cancelRequest = (requestId: string | null) => {\r\n let removed = false;\r\n captureRequestQueue = captureRequestQueue.filter((id) => {\r\n if (id !== requestId) {\r\n return true;\r\n } else {\r\n removed = true;\r\n debugLog(`In pointerEventsCapture.cancelRequest - Canceling pointer events capture request ${requestId}`);\r\n return false;\r\n }\r\n });\r\n return removed;\r\n};\r\n\r\nconst removeUnmatchedRequest = (requestId: string) => {\r\n let removed = false;\r\n unmatchedReleaseRequests = unmatchedReleaseRequests.filter((id) => {\r\n if (id !== requestId) {\r\n return true;\r\n } else {\r\n removed = true;\r\n return false;\r\n }\r\n });\r\n return removed;\r\n};\r\n\r\nconst transferPointerEventsOwnership = () => {\r\n const newOwnerId = nextCaptureRequest();\r\n debugLog(`In pointerEventsCapture.transferPointerEventsOwnership - Transferrring pointer events from ${currentOwner} to ${newOwnerId}`);\r\n // Release the current owner\r\n doRelease();\r\n if (newOwnerId) {\r\n doCapture(newOwnerId);\r\n }\r\n};\r\n\r\nconst doRelease = () => {\r\n debugLog(`In pointerEventsCapture.doRelease - Releasing pointer events from ${currentOwner}`);\r\n if (currentOwner) {\r\n // call the release callback\r\n pendingRequestCallbacks.get(currentOwner)?.release();\r\n // And remove the callbacks\r\n pendingRequestCallbacks.delete(currentOwner);\r\n currentOwner = null;\r\n }\r\n};\r\n\r\nconst doCapture = (newOwnerId: string) => {\r\n if (newOwnerId) {\r\n // call the capture callback\r\n pendingRequestCallbacks.get(newOwnerId)?.capture();\r\n }\r\n currentOwner = newOwnerId;\r\n debugLog(`In pointerEventsCapture.doCapture - Pointer events now captured by ${newOwnerId}`);\r\n};\r\n\r\nconst nextCaptureRequest = () => {\r\n return captureRequestQueue.length > 0 ? captureRequestQueue.shift() : null;\r\n};\r\n\r\n// #region Debugging support\r\ndeclare global {\r\n interface Window {\r\n // eslint-disable-next-line @typescript-eslint/naming-convention\r\n \"pointer-events-capture-debug\": boolean | null;\r\n }\r\n}\r\n\r\nconst debugLog = (message: string) => {\r\n // If we are runnning in a test runner (in node, so window is not defined)\r\n // or if the debug flag is set, then log the message\r\n if (typeof window === \"undefined\" || window[\"pointer-events-capture-debug\"]) {\r\n Tools.Log(\r\n `${performance.now()} - game.scene.pointerEvents - ${message}\\ncurrentOwner: ${currentOwner}\\nqueue: ${captureRequestQueue}\\nunmatched: ${unmatchedReleaseRequests}`\r\n );\r\n }\r\n};\r\n// #endregion Debugging support\r\n"]}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { AbstractMesh } from "@babylonjs/core/Meshes/abstractMesh.js";
|
|
2
|
+
import type { Behavior } from "@babylonjs/core/Behaviors/behavior.js";
|
|
3
|
+
/**
|
|
4
|
+
* Behavior for any content that can capture pointer events, i.e. bypass the Babylon pointer event handling
|
|
5
|
+
* and receive pointer events directly. It will register the capture triggers and negotiate the capture and
|
|
6
|
+
* release of pointer events. Curerntly this applies only to HtmlMesh
|
|
7
|
+
*/
|
|
8
|
+
export declare class PointerEventsCaptureBehavior implements Behavior<AbstractMesh> {
|
|
9
|
+
private _captureCallback;
|
|
10
|
+
private _releaseCallback;
|
|
11
|
+
/** gets or sets behavior's name */
|
|
12
|
+
name: string;
|
|
13
|
+
private _attachedMesh;
|
|
14
|
+
/** @internal */
|
|
15
|
+
_captureOnPointerEnter: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Gets or sets the mesh that the behavior is attached to
|
|
18
|
+
*/
|
|
19
|
+
get attachedMesh(): AbstractMesh | null;
|
|
20
|
+
set attachedMesh(value: AbstractMesh | null);
|
|
21
|
+
constructor(_captureCallback: () => void, _releaseCallback: () => void, { captureOnPointerEnter }?: {
|
|
22
|
+
captureOnPointerEnter?: boolean | undefined;
|
|
23
|
+
});
|
|
24
|
+
/**
|
|
25
|
+
* Set if the behavior should capture pointer events when the pointer enters the mesh
|
|
26
|
+
*/
|
|
27
|
+
set captureOnPointerEnter(captureOnPointerEnter: boolean);
|
|
28
|
+
/**
|
|
29
|
+
* Function called when the behavior needs to be initialized (before attaching it to a target)
|
|
30
|
+
*/
|
|
31
|
+
init(): void;
|
|
32
|
+
/**
|
|
33
|
+
* Called when the behavior is attached to a target
|
|
34
|
+
* @param mesh defines the target where the behavior is attached to
|
|
35
|
+
*/
|
|
36
|
+
attach(mesh: AbstractMesh): void;
|
|
37
|
+
/**
|
|
38
|
+
* Called when the behavior is detached from its target
|
|
39
|
+
*/
|
|
40
|
+
detach(): void;
|
|
41
|
+
/**
|
|
42
|
+
* Dispose the behavior
|
|
43
|
+
*/
|
|
44
|
+
dispose(): void;
|
|
45
|
+
releasePointerEvents(): void;
|
|
46
|
+
capturePointerEvents(): void;
|
|
47
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { Logger } from "@babylonjs/core/Misc/logger.js";
|
|
2
|
+
import { requestCapture, requestRelease, releaseCurrent, getCapturingId } from "./pointerEventsCapture.js";
|
|
3
|
+
// Module level variable for holding the current scene
|
|
4
|
+
let _scene = null;
|
|
5
|
+
// Module level variable to hold the count of behavior instances that are currently capturing pointer events
|
|
6
|
+
// on entry. This is used to determine if we need to start or stop observing pointer movement.
|
|
7
|
+
let captureOnEnterCount = 0;
|
|
8
|
+
// Map used to store instance of the PointerEventsCaptureBehavior for a mesh
|
|
9
|
+
// We do this because this gets checked on pointer move and we don't want to
|
|
10
|
+
// use getBehaviorByName() because that is a linear search
|
|
11
|
+
const meshToBehaviorMap = new WeakMap();
|
|
12
|
+
const startCaptureOnEnter = (scene) => {
|
|
13
|
+
// If we are not in a browser, do nothing
|
|
14
|
+
if (typeof document === "undefined") {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (captureOnEnterCount === 0) {
|
|
18
|
+
document.addEventListener("pointermove", onPointerMove);
|
|
19
|
+
document.addEventListener("touchstart", onPointerMove);
|
|
20
|
+
_scene = _scene ?? scene;
|
|
21
|
+
Logger.Log("PointerEventsCaptureBehavior: Starting observation of pointer move events.");
|
|
22
|
+
_scene.onDisposeObservable.add(doStopCaptureOnEnter);
|
|
23
|
+
}
|
|
24
|
+
captureOnEnterCount++;
|
|
25
|
+
};
|
|
26
|
+
const doStopCaptureOnEnter = () => {
|
|
27
|
+
document.removeEventListener("pointermove", onPointerMove);
|
|
28
|
+
document.removeEventListener("touchstart", onPointerMove);
|
|
29
|
+
_scene = null;
|
|
30
|
+
Logger.Log("PointerEventsCaptureBehavior: Stopping observation of pointer move events.");
|
|
31
|
+
captureOnEnterCount = 0;
|
|
32
|
+
};
|
|
33
|
+
const stopCaptureOnEnter = () => {
|
|
34
|
+
// If we are not in a browser, do nothing
|
|
35
|
+
if (typeof document === "undefined") {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
// If we are not observing pointer movement, do nothing
|
|
39
|
+
if (!_scene) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
captureOnEnterCount--;
|
|
43
|
+
if (captureOnEnterCount <= 0) {
|
|
44
|
+
doStopCaptureOnEnter();
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
// Module level function used to determine if an entered mesh should capture pointer events
|
|
48
|
+
const onPointerMove = (evt) => {
|
|
49
|
+
if (!_scene) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const canvasRect = _scene.getEngine().getRenderingCanvasClientRect();
|
|
53
|
+
if (!canvasRect) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
// Get the object that contains the client X and Y from either the pointer event or from the
|
|
57
|
+
// TouchEvent touch
|
|
58
|
+
const { clientX, clientY } = "touches" in evt ? evt.touches[0] : evt;
|
|
59
|
+
// get the picked mesh, if any
|
|
60
|
+
const pointerScreenX = clientX - canvasRect.left;
|
|
61
|
+
const pointerScreenY = clientY - canvasRect.top;
|
|
62
|
+
let pointerCaptureBehavior;
|
|
63
|
+
const pickResult = _scene.pick(pointerScreenX, pointerScreenY, (mesh) => {
|
|
64
|
+
// If the mesh has an instance of PointerEventsCaptureBehavior attached to it,
|
|
65
|
+
// and capture on pointer enter is true, then we want to pick it
|
|
66
|
+
const pointerCaptureBehavior = meshToBehaviorMap.get(mesh);
|
|
67
|
+
return mesh.isEnabled() && typeof pointerCaptureBehavior !== "undefined" && pointerCaptureBehavior._captureOnPointerEnter;
|
|
68
|
+
});
|
|
69
|
+
let pickedMesh;
|
|
70
|
+
if (pickResult.hit) {
|
|
71
|
+
pickedMesh = pickResult.pickedMesh;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
pickedMesh = null;
|
|
75
|
+
}
|
|
76
|
+
const capturingIdAsInt = parseInt(getCapturingId() || "");
|
|
77
|
+
// if the picked mesh is the current capturing mesh, do nothing
|
|
78
|
+
if (pickedMesh && pickedMesh.uniqueId === capturingIdAsInt) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
// If there is a capturing mesh and it is not the current picked mesh, or no
|
|
82
|
+
// mesh is picked, release the capturing mesh
|
|
83
|
+
if (capturingIdAsInt && (!pickedMesh || pickedMesh.uniqueId !== capturingIdAsInt)) {
|
|
84
|
+
releaseCurrent();
|
|
85
|
+
}
|
|
86
|
+
// If there is a picked mesh and it is not the current capturing mesh, capture
|
|
87
|
+
// the pointer events. Note that the current capturing mesh has already been
|
|
88
|
+
// released above
|
|
89
|
+
if (pickedMesh) {
|
|
90
|
+
pointerCaptureBehavior = meshToBehaviorMap.get(pickedMesh);
|
|
91
|
+
pointerCaptureBehavior.capturePointerEvents();
|
|
92
|
+
}
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Behavior for any content that can capture pointer events, i.e. bypass the Babylon pointer event handling
|
|
96
|
+
* and receive pointer events directly. It will register the capture triggers and negotiate the capture and
|
|
97
|
+
* release of pointer events. Curerntly this applies only to HtmlMesh
|
|
98
|
+
*/
|
|
99
|
+
export class PointerEventsCaptureBehavior {
|
|
100
|
+
/**
|
|
101
|
+
* Gets or sets the mesh that the behavior is attached to
|
|
102
|
+
*/
|
|
103
|
+
get attachedMesh() {
|
|
104
|
+
return this._attachedMesh;
|
|
105
|
+
}
|
|
106
|
+
set attachedMesh(value) {
|
|
107
|
+
this._attachedMesh = value;
|
|
108
|
+
}
|
|
109
|
+
constructor(_captureCallback, _releaseCallback, { captureOnPointerEnter = true } = {}) {
|
|
110
|
+
this._captureCallback = _captureCallback;
|
|
111
|
+
this._releaseCallback = _releaseCallback;
|
|
112
|
+
/** gets or sets behavior's name */
|
|
113
|
+
this.name = "PointerEventsCaptureBehavior";
|
|
114
|
+
this._attachedMesh = null;
|
|
115
|
+
this._captureOnPointerEnter = captureOnPointerEnter;
|
|
116
|
+
// Warn if we are not in a browser
|
|
117
|
+
if (typeof document === "undefined") {
|
|
118
|
+
Logger.Warn(`Creating an instance of PointerEventsCaptureBehavior outside of a browser. The behavior will not work.`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Set if the behavior should capture pointer events when the pointer enters the mesh
|
|
123
|
+
*/
|
|
124
|
+
set captureOnPointerEnter(captureOnPointerEnter) {
|
|
125
|
+
if (this._captureOnPointerEnter === captureOnPointerEnter) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
this._captureOnPointerEnter = captureOnPointerEnter;
|
|
129
|
+
if (this._attachedMesh) {
|
|
130
|
+
if (this._captureOnPointerEnter) {
|
|
131
|
+
startCaptureOnEnter(this._attachedMesh.getScene());
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
stopCaptureOnEnter();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Function called when the behavior needs to be initialized (before attaching it to a target)
|
|
140
|
+
*/
|
|
141
|
+
init() { }
|
|
142
|
+
/**
|
|
143
|
+
* Called when the behavior is attached to a target
|
|
144
|
+
* @param mesh defines the target where the behavior is attached to
|
|
145
|
+
*/
|
|
146
|
+
attach(mesh) {
|
|
147
|
+
// Add a reference to this behavior on the mesh. We do this so we can get a
|
|
148
|
+
// reference to the behavior in the onPointerMove function without relying on
|
|
149
|
+
// getBehaviorByName(), which does a linear search of the behaviors array.
|
|
150
|
+
this.attachedMesh = mesh;
|
|
151
|
+
meshToBehaviorMap.set(mesh, this);
|
|
152
|
+
if (this._captureOnPointerEnter) {
|
|
153
|
+
startCaptureOnEnter(mesh.getScene());
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Called when the behavior is detached from its target
|
|
158
|
+
*/
|
|
159
|
+
detach() {
|
|
160
|
+
if (!this.attachedMesh) {
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
// Remove the reference to this behavior from the mesh
|
|
164
|
+
meshToBehaviorMap.delete(this.attachedMesh);
|
|
165
|
+
if (this._captureOnPointerEnter) {
|
|
166
|
+
stopCaptureOnEnter();
|
|
167
|
+
}
|
|
168
|
+
this.attachedMesh = null;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Dispose the behavior
|
|
172
|
+
*/
|
|
173
|
+
dispose() {
|
|
174
|
+
this.detach();
|
|
175
|
+
}
|
|
176
|
+
// Release pointer events
|
|
177
|
+
releasePointerEvents() {
|
|
178
|
+
if (!this.attachedMesh) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
requestRelease(this.attachedMesh.uniqueId.toString());
|
|
182
|
+
}
|
|
183
|
+
// Capture pointer events
|
|
184
|
+
capturePointerEvents() {
|
|
185
|
+
if (!this.attachedMesh) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
requestCapture(this.attachedMesh.uniqueId.toString(), this._captureCallback, this._releaseCallback);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=pointerEventsCaptureBehavior.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pointerEventsCaptureBehavior.js","sourceRoot":"","sources":["../../../../dev/addons/src/htmlMesh/pointerEventsCaptureBehavior.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AbstractMesh } from \"core/Meshes/abstractMesh\";\r\nimport type { Behavior } from \"core/Behaviors/behavior\";\r\nimport type { Scene } from \"core/scene\";\r\nimport { Logger } from \"core/Misc/logger\";\r\nimport { requestCapture, requestRelease, releaseCurrent, getCapturingId } from \"./pointerEventsCapture\";\r\n\r\n// Module level variable for holding the current scene\r\nlet _scene: Scene | null = null;\r\n\r\n// Module level variable to hold the count of behavior instances that are currently capturing pointer events\r\n// on entry. This is used to determine if we need to start or stop observing pointer movement.\r\nlet captureOnEnterCount = 0;\r\n\r\n// Map used to store instance of the PointerEventsCaptureBehavior for a mesh\r\n// We do this because this gets checked on pointer move and we don't want to\r\n// use getBehaviorByName() because that is a linear search\r\nconst meshToBehaviorMap = new WeakMap<AbstractMesh, PointerEventsCaptureBehavior>();\r\n\r\nconst startCaptureOnEnter = (scene: Scene) => {\r\n // If we are not in a browser, do nothing\r\n if (typeof document === \"undefined\") {\r\n return;\r\n }\r\n if (captureOnEnterCount === 0) {\r\n document.addEventListener(\"pointermove\", onPointerMove);\r\n document.addEventListener(\"touchstart\", onPointerMove);\r\n _scene = _scene ?? scene;\r\n Logger.Log(\"PointerEventsCaptureBehavior: Starting observation of pointer move events.\");\r\n _scene.onDisposeObservable.add(doStopCaptureOnEnter);\r\n }\r\n captureOnEnterCount++;\r\n};\r\n\r\nconst doStopCaptureOnEnter = () => {\r\n document.removeEventListener(\"pointermove\", onPointerMove);\r\n document.removeEventListener(\"touchstart\", onPointerMove);\r\n _scene = null;\r\n Logger.Log(\"PointerEventsCaptureBehavior: Stopping observation of pointer move events.\");\r\n captureOnEnterCount = 0;\r\n};\r\n\r\nconst stopCaptureOnEnter = () => {\r\n // If we are not in a browser, do nothing\r\n if (typeof document === \"undefined\") {\r\n return;\r\n }\r\n\r\n // If we are not observing pointer movement, do nothing\r\n if (!_scene) {\r\n return;\r\n }\r\n\r\n captureOnEnterCount--;\r\n if (captureOnEnterCount <= 0) {\r\n doStopCaptureOnEnter();\r\n }\r\n};\r\n\r\n// Module level function used to determine if an entered mesh should capture pointer events\r\nconst onPointerMove = (evt: PointerEvent | TouchEvent) => {\r\n if (!_scene) {\r\n return;\r\n }\r\n\r\n const canvasRect = _scene.getEngine().getRenderingCanvasClientRect();\r\n if (!canvasRect) {\r\n return;\r\n }\r\n\r\n // Get the object that contains the client X and Y from either the pointer event or from the\r\n // TouchEvent touch\r\n const { clientX, clientY } = \"touches\" in evt ? evt.touches[0] : evt;\r\n\r\n // get the picked mesh, if any\r\n const pointerScreenX = clientX - canvasRect.left;\r\n const pointerScreenY = clientY - canvasRect.top;\r\n\r\n let pointerCaptureBehavior: PointerEventsCaptureBehavior | undefined;\r\n const pickResult = _scene.pick(pointerScreenX, pointerScreenY, (mesh) => {\r\n // If the mesh has an instance of PointerEventsCaptureBehavior attached to it,\r\n // and capture on pointer enter is true, then we want to pick it\r\n const pointerCaptureBehavior = meshToBehaviorMap.get(mesh);\r\n return mesh.isEnabled() && typeof pointerCaptureBehavior !== \"undefined\" && pointerCaptureBehavior._captureOnPointerEnter;\r\n });\r\n\r\n let pickedMesh: AbstractMesh | null;\r\n if (pickResult.hit) {\r\n pickedMesh = pickResult.pickedMesh;\r\n } else {\r\n pickedMesh = null;\r\n }\r\n\r\n const capturingIdAsInt = parseInt(getCapturingId() || \"\");\r\n\r\n // if the picked mesh is the current capturing mesh, do nothing\r\n if (pickedMesh && pickedMesh.uniqueId === capturingIdAsInt) {\r\n return;\r\n }\r\n\r\n // If there is a capturing mesh and it is not the current picked mesh, or no\r\n // mesh is picked, release the capturing mesh\r\n if (capturingIdAsInt && (!pickedMesh || pickedMesh.uniqueId !== capturingIdAsInt)) {\r\n releaseCurrent();\r\n }\r\n\r\n // If there is a picked mesh and it is not the current capturing mesh, capture\r\n // the pointer events. Note that the current capturing mesh has already been\r\n // released above\r\n if (pickedMesh) {\r\n pointerCaptureBehavior = meshToBehaviorMap.get(pickedMesh);\r\n pointerCaptureBehavior!.capturePointerEvents();\r\n }\r\n};\r\n\r\n/**\r\n * Behavior for any content that can capture pointer events, i.e. bypass the Babylon pointer event handling\r\n * and receive pointer events directly. It will register the capture triggers and negotiate the capture and\r\n * release of pointer events. Curerntly this applies only to HtmlMesh\r\n */\r\nexport class PointerEventsCaptureBehavior implements Behavior<AbstractMesh> {\r\n /** gets or sets behavior's name */\r\n public name = \"PointerEventsCaptureBehavior\";\r\n\r\n private _attachedMesh: AbstractMesh | null;\r\n /** @internal */\r\n public _captureOnPointerEnter: boolean;\r\n\r\n /**\r\n * Gets or sets the mesh that the behavior is attached to\r\n */\r\n public get attachedMesh() {\r\n return this._attachedMesh;\r\n }\r\n\r\n public set attachedMesh(value: AbstractMesh | null) {\r\n this._attachedMesh = value;\r\n }\r\n\r\n constructor(\r\n private _captureCallback: () => void,\r\n private _releaseCallback: () => void,\r\n { captureOnPointerEnter = true } = {}\r\n ) {\r\n this._attachedMesh = null;\r\n this._captureOnPointerEnter = captureOnPointerEnter;\r\n\r\n // Warn if we are not in a browser\r\n if (typeof document === \"undefined\") {\r\n Logger.Warn(`Creating an instance of PointerEventsCaptureBehavior outside of a browser. The behavior will not work.`);\r\n }\r\n }\r\n\r\n /**\r\n * Set if the behavior should capture pointer events when the pointer enters the mesh\r\n */\r\n public set captureOnPointerEnter(captureOnPointerEnter: boolean) {\r\n if (this._captureOnPointerEnter === captureOnPointerEnter) {\r\n return;\r\n }\r\n this._captureOnPointerEnter = captureOnPointerEnter;\r\n if (this._attachedMesh) {\r\n if (this._captureOnPointerEnter) {\r\n startCaptureOnEnter(this._attachedMesh.getScene()!);\r\n } else {\r\n stopCaptureOnEnter();\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Function called when the behavior needs to be initialized (before attaching it to a target)\r\n */\r\n public init() {}\r\n\r\n /**\r\n * Called when the behavior is attached to a target\r\n * @param mesh defines the target where the behavior is attached to\r\n */\r\n public attach(mesh: AbstractMesh) {\r\n // Add a reference to this behavior on the mesh. We do this so we can get a\r\n // reference to the behavior in the onPointerMove function without relying on\r\n // getBehaviorByName(), which does a linear search of the behaviors array.\r\n this.attachedMesh = mesh;\r\n meshToBehaviorMap.set(mesh, this);\r\n if (this._captureOnPointerEnter) {\r\n startCaptureOnEnter(mesh.getScene()!);\r\n }\r\n }\r\n\r\n /**\r\n * Called when the behavior is detached from its target\r\n */\r\n public detach() {\r\n if (!this.attachedMesh) {\r\n return;\r\n }\r\n // Remove the reference to this behavior from the mesh\r\n meshToBehaviorMap.delete(this.attachedMesh);\r\n if (this._captureOnPointerEnter) {\r\n stopCaptureOnEnter();\r\n }\r\n this.attachedMesh = null;\r\n }\r\n\r\n /**\r\n * Dispose the behavior\r\n */\r\n public dispose() {\r\n this.detach();\r\n }\r\n\r\n // Release pointer events\r\n public releasePointerEvents() {\r\n if (!this.attachedMesh) {\r\n return;\r\n }\r\n requestRelease(this.attachedMesh.uniqueId.toString());\r\n }\r\n\r\n // Capture pointer events\r\n public capturePointerEvents() {\r\n if (!this.attachedMesh) {\r\n return;\r\n }\r\n requestCapture(this.attachedMesh.uniqueId.toString(), this._captureCallback, this._releaseCallback);\r\n }\r\n}\r\n"]}
|
package/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export * from "./htmlMesh";
|
package/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export
|
|
1
|
+
export * from "./htmlMesh.js";
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../dev/addons/src/index.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../dev/addons/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC","sourcesContent":["export * from \"./htmlMesh\";\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@babylonjs/addons",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.34.0",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"module": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"postcompile": "build-tools -c add-js-to-es6"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
|
-
"@babylonjs/core": "^7.
|
|
21
|
+
"@babylonjs/core": "^7.34.0",
|
|
22
22
|
"@dev/addons": "^1.0.0",
|
|
23
23
|
"@dev/build-tools": "^1.0.0"
|
|
24
24
|
},
|