diff --git a/src/framework/xr/xr-anchors.js b/src/framework/xr/xr-anchors.js index 2b950392f7b..9b17a9b0bb6 100644 --- a/src/framework/xr/xr-anchors.js +++ b/src/framework/xr/xr-anchors.js @@ -26,12 +26,24 @@ import { XrAnchor } from './xr-anchor.js'; * @category XR */ class XrAnchors extends EventHandler { + /** + * @type {import('./xr-manager.js').XrManager} + * @ignore + */ + manager; + /** * @type {boolean} * @private */ _supported = platform.browser && !!window.XRAnchor; + /** + * @type {boolean} + * @private + */ + _available = false; + /** * @type {boolean} * @private @@ -87,10 +99,23 @@ class XrAnchors extends EventHandler { this.manager = manager; if (this._supported) { + this.manager.on('start', this._onSessionStart, this); this.manager.on('end', this._onSessionEnd, this); } } + /** + * Fired when anchors becomes available. + * + * @event XrAnchors#available + */ + + /** + * Fired when anchors becomes unavailable. + * + * @event XrAnchors#unavailable + */ + /** * Fired when anchor failed to be created. * @@ -120,8 +145,19 @@ class XrAnchors extends EventHandler { * }); */ + /** @private */ + _onSessionStart() { + const available = this.manager.session.enabledFeatures.indexOf('anchors') !== -1; + if (!available) return; + this._available = available; + this.fire('available'); + } + /** @private */ _onSessionEnd() { + if (!this._available) return; + this._available = false; + // clear anchor creation queue for (let i = 0; i < this._creationQueue.length; i++) { if (!this._creationQueue[i].callback) @@ -140,6 +176,8 @@ class XrAnchors extends EventHandler { this._list[i].destroy(); } this._list.length = 0; + + this.fire('unavailable'); } /** @@ -194,6 +232,11 @@ class XrAnchors extends EventHandler { * }); */ create(position, rotation, callback) { + if (!this._available) { + callback?.(new Error('Anchors API is not available'), null); + return; + } + // eslint-disable-next-line no-undef if (window.XRHitTestResult && position instanceof XRHitTestResult) { const hitResult = position; @@ -247,6 +290,11 @@ class XrAnchors extends EventHandler { * } */ restore(uuid, callback) { + if (!this._available) { + callback?.(new Error('Anchors API is not available'), null); + return; + } + if (!this._persistence) { callback?.(new Error('Anchor Persistence is not supported'), null); return; @@ -283,6 +331,11 @@ class XrAnchors extends EventHandler { * } */ forget(uuid, callback) { + if (!this._available) { + callback?.(new Error('Anchors API is not available')); + return; + } + if (!this._persistence) { callback?.(new Error('Anchor Persistence is not supported')); return; @@ -308,6 +361,9 @@ class XrAnchors extends EventHandler { * @ignore */ update(frame) { + if (!this._available) + return; + // check if need to create anchors if (this._creationQueue.length) { for (let i = 0; i < this._creationQueue.length; i++) { @@ -378,6 +434,15 @@ class XrAnchors extends EventHandler { return this._supported; } + /** + * True if Anchors are available. This information is available only when session has started. + * + * @type {boolean} + */ + get available() { + return this._available; + } + /** * True if Anchors support persistence. * @@ -393,6 +458,9 @@ class XrAnchors extends EventHandler { * @type {null|string[]} */ get uuids() { + if (!this._available) + return null; + if (!this._persistence) return null;