Start · Sprachen · JavaScript · Referenz · XRSession: selectstart

XRSession: selectstart

Ereignis

Wird an eine <code>XRSession</code> gesendet, sobald der Benutzer eine Primäraktion (z. B. Trigger drücken, Pinch-Geste, Tippen auf den Bildschirm) auf einer Eingabequelle beginnt.

seit JavaScript WebXR Device API – Chromium-Browser (Chrome/Edge 7 Kategorie: webapi

Signatur

xrSession.addEventListener("selectstart", handler)

Beschreibung

Das Ereignis selectstart gehört zu den Eingabe-Ereignissen der WebXR Device API. Es wird ausgelöst, wenn eine Eingabequelle (XRInputSource) ihre Primäraktion beginnt. Das kann der Trigger eines VR-Controllers sein, eine Pinch-Geste beim Hand-Tracking, ein Blick mit Bestätigung oder ein Tippen auf den Bildschirm in einer AR-Sitzung auf dem Smartphone. Du kannst es mit addEventListener("selectstart", …) oder über die Eigenschaft XRSession.onselectstart abonnieren.

Zusammen mit selectend und select bildet es einen vollständigen Aktionszyklus: selectstart → (Aktion läuft) → select (nur bei erfolgreichem Abschluss) → selectend. selectstart eignet sich deshalb für Interaktionen, die beim Drücken beginnen und bis zum Loslassen andauern, etwa Greifen und Ziehen von Objekten, Laden eines Schusses oder Zeichnen im Raum.

Der Handler bekommt ein XRInputSourceEvent. Dessen Eigenschaft inputSource nennt die auslösende Eingabequelle, frame ist ein XRFrame, der nur während des Handlers gültig ist. Über frame.getPose(inputSource.targetRaySpace, referenceSpace) fragst du ab, wohin der Zeigestrahl im Moment des Drückens zeigt.

Parameter

Name Typ Default Beschreibung
$type Pflicht string Der Ereignistyp, hier immer "selectstart".
$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, signal oder capture.

Rückgabewert

Typ
void
Beschreibung
addEventListener gibt nichts zurück. Der Handler wird mit einem XRInputSourceEvent aufgerufen.

Beispiele

Primäraktion erkennen und Zeigestrahl auslesen

const session = await navigator.xr.requestSession('immersive-vr');
const refSpace = await session.requestReferenceSpace('local');

session.addEventListener('selectstart', (event) => {
  const { inputSource, frame } = event;
  // Pose des Zeigestrahls zum Zeitpunkt des Drückens
  const pose = frame.getPose(inputSource.targetRaySpace, refSpace);
  if (pose) {
    const { x, y, z } = pose.transform.position;
    console.log(`selectstart (${inputSource.handedness}) bei`, x.toFixed(2), y.toFixed(2), z.toFixed(2));
  }
});
selectstart (right) bei 0.21 1.35 -0.30

Greifen und Ziehen mit selectstart/selectend

const grabbing = new Map(); // inputSource -> Objekt

const onSelectStart = (event) => {
  const target = findObjectUnderRay(event.inputSource, event.frame); // eigene Trefferprüfung
  if (target) {
    grabbing.set(event.inputSource, target);
    target.highlight = true;
  }
};

const onSelectEnd = (event) => {
  const obj = grabbing.get(event.inputSource);
  if (obj) {
    obj.highlight = false;
    grabbing.delete(event.inputSource);
  }
};

session.addEventListener('selectstart', onSelectStart);
session.addEventListener('selectend', onSelectEnd);

// Im Render-Loop: gegriffene Objekte der Controller-Pose folgen lassen
const onFrame = (time, frame) => {
  for (const [source, obj] of grabbing) {
    const pose = frame.getPose(source.gripSpace ?? source.targetRaySpace, refSpace);
    if (pose) obj.matrix = pose.transform.matrix;
  }
  session.requestAnimationFrame(onFrame);
};
session.requestAnimationFrame(onFrame);

on-Property verwenden und Listener wieder entfernen

// Variante über die Event-Handler-Eigenschaft
session.onselectstart = (event) => {
  console.log('Aktion gestartet von', event.inputSource.targetRayMode);
};

// Variante mit AbortController zum sauberen Entfernen
const controller = new AbortController();
session.addEventListener('selectstart', (e) => console.log('Start'), { signal: controller.signal });

session.addEventListener('end', () => {
  controller.abort();          // Listener entfernen
  session.onselectstart = null; // Property-Handler entfernen
});
Aktion gestartet von tracked-pointer

// Wichtig · Fallstricke

  • Frame nur im Handler gültig: event.frame ist inaktiv, sobald der Handler endet. Speicherst du ihn und rufst später getPose() auf, wird ein InvalidStateError geworfen. Brauchst du die Pose später, lies sie sofort aus.
  • Nicht jedes selectstart endet mit select: Wird die Aktion abgebrochen, z. B. weil der Controller die Verbindung verliert oder die Sitzung endet, folgt nur selectend ohne select. Räume Zustand wie gegriffene Objekte deshalb immer in selectend auf.
  • Mehrere Eingabequellen: Beide Hände oder Controller können gleichzeitig Aktionen auslösen. Ordne Zustände immer über event.inputSource zu, nie global.
  • Transiente Eingaben: Bei targetRayMode === "screen" (AR-Touch) wird die Eingabequelle erst unmittelbar vor selectstart erzeugt und verschwindet nach selectend wieder.
  • Sekundäraktionen wie der Grip-Button lösen stattdessen squeezestart aus.
  • Kompatibilität: WebXR braucht einen sicheren Kontext (HTTPS) und wird von Chromium-Browsern sowie dem Meta Quest Browser unterstützt. Firefox und Safari auf dem Desktop bieten keine Unterstützung, visionOS nur eingeschränkt. Prüfe vorher mit navigator.xr?.isSessionSupported().