Signatur
Beschreibung
Das Ereignis selectend gehört zu den drei Auswahl-Ereignissen der WebXR Device API: selectstart, select und selectend. Es wird ausgelöst, sobald die primäre Aktion einer Eingabequelle endet. Das kann z. B. das Loslassen des Trigger-Knopfs am Controller sein, das Ende einer Pinch-Geste beim Hand-Tracking oder das Abheben des Fingers vom Bildschirm in einer AR-Sitzung auf dem Smartphone.
Wichtig: selectend wird immer ausgelöst, wenn vorher ein selectstart kam. Das gilt auch, wenn die Aktion abgebrochen wurde, etwa weil der Controller getrennt wurde oder die Sitzung endet. select dagegen wird nur bei einer erfolgreich abgeschlossenen Aktion ausgelöst, und zwar vor selectend. Deshalb ist selectend der richtige Ort für Aufräumarbeiten: gegriffene Objekte loslassen, Hervorhebungen entfernen oder Zustandsvariablen zurücksetzen.
Der Handler bekommt ein XRInputSourceEvent. Dessen Eigenschaft inputSource gibt an, welche Eingabequelle betroffen ist (z. B. linke oder rechte Hand). Über frame kommt man an ein XRFrame, mit dem sich die Pose der Eingabequelle zum Zeitpunkt des Ereignisses abfragen lässt. Registrieren kann man den Handler mit addEventListener("selectend", …) oder über die Eigenschaft onselectend.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Der Ereignisname "selectend". |
|
| $handler Pflicht | (event: XRInputSourceEvent) => void | Callback, der ein XRInputSourceEvent mit den Eigenschaften inputSource (XRInputSource) und frame (XRFrame) erhält. |
|
| $options | boolean | AddEventListenerOptions | false | Übliche Listener-Optionen wie once oder signal. |
Rückgabewert
addEventListener gibt nichts zurück. Der Rückgabewert des Handlers wird nicht ausgewertet.Beispiele
Gegriffenes Objekt beim Loslassen freigeben
const session = await navigator.xr.requestSession('immersive-vr');
const refSpace = await session.requestReferenceSpace('local');
// Pro Eingabequelle merken, welches Objekt gehalten wird
const held = new Map();
session.addEventListener('selectstart', (event) => {
held.set(event.inputSource, { name: 'Würfel' });
console.log(`Greifen gestartet (${event.inputSource.handedness})`);
});
session.addEventListener('selectend', (event) => {
const obj = held.get(event.inputSource);
if (!obj) return;
// Pose zum Zeitpunkt des Loslassens bestimmen
const pose = event.frame.getPose(event.inputSource.targetRaySpace, refSpace);
if (pose) {
const { x, y, z } = pose.transform.position;
console.log(`${obj.name} losgelassen bei`, x.toFixed(2), y.toFixed(2), z.toFixed(2));
}
held.delete(event.inputSource);
});
Abbruch von erfolgreicher Auswahl unterscheiden
const session = await navigator.xr.requestSession('immersive-ar');
let completed = false;
session.addEventListener('selectstart', () => { completed = false; });
// 'select' kommt nur bei erfolgreich abgeschlossener Aktion, vor 'selectend'
session.addEventListener('select', () => { completed = true; });
session.addEventListener('selectend', () => {
console.log(completed ? 'Aktion abgeschlossen' : 'Aktion abgebrochen (z. B. Controller getrennt)');
});
on-Property verwenden und wieder entfernen
const session = await navigator.xr.requestSession('immersive-vr');
const onSelectEnd = (event) => {
console.log('selectend von', event.inputSource.targetRayMode);
};
// Variante 1: on-Property
session.onselectend = onSelectEnd;
// Variante 2: addEventListener, später wieder entfernen
session.addEventListener('selectend', onSelectEnd);
session.removeEventListener('selectend', onSelectEnd);
// on-Property zurücksetzen
session.onselectend = null;
// Wichtig · Fallstricke
- Immer aufräumen:
selectendkommt auch bei Abbruch (Controller getrennt, Sitzung beendet). Erfolgsaktionen gehören deshalb inselect, Aufräumarbeiten inselectend. - Das übergebene
event.framegilt nur während des Handlers.getPose()darf also nicht asynchron danach aufgerufen werden, sonst kommt es zu einemInvalidStateError. - Mehrere Eingabequellen, etwa zwei Controller, können gleichzeitig aktiv sein. Den Zustand deshalb pro
inputSourceverwalten, nicht in einer globalen Variable. - Für den sekundären Knopf (Grip/Squeeze) gibt es die eigenen Ereignisse
squeezestart,squeezeundsqueezeend. - Kompatibilität: WebXR funktioniert nur in sicheren Kontexten (HTTPS) und wird hauptsächlich von Chromium-Browsern und dem Meta Quest Browser unterstützt. Firefox und Safari (Desktop) unterstützen es nicht; Safari auf visionOS unterstützt WebXR. Vorher mit
navigator.xr?.isSessionSupported()prüfen.