Quellcode durchsuchen

docs: add pointer events examples and documentation (#1066)

- Introduced two new Vue components for demonstrating pointer events: `index.vue` and `propagation.vue`, showcasing click, pointer enter, and pointer leave interactions with TresJS.
- Added a new navigation entry for "Event handling" and created a detailed documentation page on pointer events, explaining their usage and available events in TresJS.
- Updated the existing `groups/index.vue` to handle pointer missed events, enhancing interactivity in the playground.
- Included performance considerations and best practices for using pointer events effectively in 3D applications.
Alvaro Saburido vor 1 Tag
Ursprung
Commit
8ae7554053

+ 47 - 0
docs/app/components/examples/pointer-events/index.vue

@@ -0,0 +1,47 @@
+<script setup lang="ts">
+import { TresCanvas } from '@tresjs/core'
+
+const toast = useToast()
+
+const handleClick = (event: PointerEvent) => {
+  toast.add({
+    title: 'BoxClicked',
+    description: `X: ${event.clientX}, Y: ${event.clientY}`,
+  })
+}
+
+const handlePointerEnter = (event: PointerEvent) => {
+  toast.add({
+    title: 'Pointer entered the box!',
+    description: `X: ${event.clientX}, Y: ${event.clientY}`,
+  })
+}
+
+const handlePointerLeave = (event: PointerEvent) => {
+  toast.add({
+    title: 'Pointer left the box!',
+    description: `X: ${event.clientX}, Y: ${event.clientY}`,
+  })
+}
+</script>
+
+<template>
+  <SceneWrapper>
+    <TresCanvas
+      clear-color="#82DBC5"
+    >
+      <TresPerspectiveCamera
+        :position="[2, 2, 2]"
+        :look-at="[0, 0, 0]"
+      />
+      <TresMesh
+        @click="handleClick"
+        @pointerenter="handlePointerEnter"
+        @pointerleave="handlePointerLeave"
+      >
+        <TresBoxGeometry />
+        <TresMeshNormalMaterial />
+      </TresMesh>
+    </TresCanvas>
+  </SceneWrapper>
+</template>

+ 47 - 0
docs/app/components/examples/pointer-events/propagation.vue

@@ -0,0 +1,47 @@
+<script setup lang="ts">
+import { TresCanvas } from '@tresjs/core'
+import { TresLeches, useControls } from '@tresjs/leches'
+
+const { stopPropagation } = useControls({
+  stopPropagation: false,
+}, {
+  uuid: 'pointer-events-propagation',
+})
+
+const toast = useToast()
+
+function onChildClick(event: PointerEvent) {
+  if (stopPropagation?.value) {
+    event.stopPropagation() // Prevents parent from receiving the event
+  }
+  toast.add({
+    title: 'Child clicked!',
+    description: `X: ${event.clientX}, Y: ${event.clientY}`,
+  })
+}
+
+function onParentClick(event: PointerEvent) {
+  toast.add({
+    title: 'Parent clicked!',
+    description: `X: ${event.clientX}, Y: ${event.clientY}`,
+  })
+}
+</script>
+
+<template>
+  <SceneWrapper>
+    <TresLeches uuid="pointer-events-propagation" />
+    <TresCanvas clear-color="#82DBC5">
+      <TresPerspectiveCamera
+        :position="[2, 2, 2]"
+        :look-at="[0, 0, 0]"
+      />
+      <TresGroup @click="onParentClick">
+        <TresMesh @click="onChildClick">
+          <TresBoxGeometry />
+          <TresMeshNormalMaterial />
+        </TresMesh>
+      </TresGroup>
+    </TresCanvas>
+  </SceneWrapper>
+</template>

+ 2 - 0
docs/content/3.api/3.events/.navigation.yml

@@ -0,0 +1,2 @@
+title: Event handling
+icon: i-lucide-mouse-pointer-2

+ 166 - 0
docs/content/3.api/3.events/1.pointer-events.md

@@ -0,0 +1,166 @@
+---
+title: Pointer Events
+description: Explore the TresJS pointer events system powered by @pmndrs/pointer-events.
+---
+
+TresJS provides a comprehensive pointer events system that allows you to interact with 3D objects using mouse, touch, and other pointer devices. The event system is built on top of the powerful [`@pmndrs/pointer-events`](https://www.npmjs.com/package/@pmndrs/pointer-events) package, providing framework-agnostic pointer event handling for Three.js objects.
+
+## Basic Usage
+
+Pointer events are automatically enabled in `TresCanvas` and work seamlessly with all 3D objects. Simply add event listeners directly to your TresJS components:
+
+::examples-pointer-events
+::
+
+```vue
+<script setup lang="ts">
+import { ref } from 'vue'
+
+const boxRef = ref()
+
+function onPointerEnter() {
+  console.log('Pointer entered the box!')
+}
+
+function onPointerLeave() {
+  console.log('Pointer left the box!')
+}
+
+function onClick() {
+  console.log('Box clicked!')
+}
+</script>
+
+<template>
+  <TresCanvas>
+    <TresMesh
+      ref="boxRef"
+      @pointerenter="onPointerEnter"
+      @pointerleave="onPointerLeave"
+      @click="onClick"
+    >
+      <TresBoxGeometry />
+      <TresMeshNormalMaterial />
+    </TresMesh>
+  </TresCanvas>
+</template>
+```
+
+## Available Events
+
+TresJS supports all standard pointer events that you can listen to on any 3D object:
+
+### Mouse Events
+- `@click` - Fired when the object is clicked
+- `@doubleclick` - Fired when the object is double-clicked
+- `@contextmenu` - Fired when right-clicking the object
+- `@pointerdown` - Fired when pointer is pressed down on the object
+- `@pointerup` - Fired when pointer is released over the object
+
+### Hover Events
+- `@pointerenter` - Fired when pointer enters the object's bounds
+- `@pointerleave` - Fired when pointer leaves the object's bounds
+- `@pointerover` - Fired when pointer is over the object
+- `@pointerout` - Fired when pointer moves away from the object
+- `@pointermove` - Fired when pointer moves while over the object
+
+### Drag Events
+- `@pointercancel` - Fired when pointer interaction is cancelled
+
+## Event Objects
+
+Event handlers receive a `PointerEvent` object with useful information:
+
+```vue
+<script setup lang="ts">
+function onPointerMove(event) {
+  console.log('Pointer position:', event.point) // 3D world position
+  console.log('Screen coordinates:', event.xy) // 2D screen coordinates
+  console.log('Object hit:', event.object) // The Three.js object that was hit
+  console.log('Distance:', event.distance) // Distance from camera to hit point
+  console.log('Face:', event.face) // The face that was intersected
+  console.log('UV coordinates:', event.uv) // UV coordinates at hit point
+}
+</script>
+
+<template>
+  <TresMesh @pointermove="onPointerMove">
+    <TresBoxGeometry />
+    <TresMeshNormalMaterial />
+  </TresMesh>
+</template>
+```
+
+## Pointer Missed Events
+
+You can listen for events when the pointer misses all objects (clicks on empty space) by adding the `@pointermissed` event directly to the `TresCanvas` component:
+
+```vue
+<script setup lang="ts">
+function onPointerMissed(event) {
+  console.log('Clicked on empty space')
+  // Useful for deselecting objects, closing menus, etc.
+}
+</script>
+
+<template>
+  <TresCanvas @pointermissed="onPointerMissed">
+    <!-- Your 3D objects here -->
+    <TresMesh>
+      <TresBoxGeometry />
+      <TresMeshNormalMaterial />
+    </TresMesh>
+  </TresCanvas>
+</template>
+```
+
+## Event Propagation
+
+Events bubble up through the 3D object hierarchy. You can stop propagation using the standard event methods:
+
+::examples-pointer-events-propagation
+::
+
+```vue
+<script setup lang="ts">
+function onChildClick(event) {
+  event.stopPropagation() // Prevents parent from receiving the event
+  console.log('Child clicked!')
+}
+
+function onParentClick() {
+  console.log('Parent clicked!') // Won't fire if child stops propagation
+}
+</script>
+
+<template>
+  <TresGroup @click="onParentClick">
+    <TresMesh @click="onChildClick">
+      <TresBoxGeometry />
+      <TresMeshNormalMaterial />
+    </TresMesh>
+  </TresGroup>
+</template>
+```
+
+## Performance Considerations
+
+- Events are automatically optimized using raycasting
+- Only objects with event listeners are tested for intersections
+- Use `pointer-events: none` in CSS to disable interaction on specific objects
+- Consider using object pooling for scenes with many interactive objects
+
+## TypeScript Support
+
+TresJS provides full TypeScript support for pointer events:
+
+```ts
+import type { PointerEvent } from '@pmndrs/pointer-events'
+
+function handlePointerEvent(event: PointerEvent<MouseEvent>) {
+  // Full type safety for event properties
+  console.log(event.point) // Vector3
+  console.log(event.object) // Object3D
+  console.log(event.xy) // [number, number]
+}
+```

+ 0 - 0
docs/content/3.api/3.advanced/.navigation.yml → docs/content/3.api/4.advanced/.navigation.yml


+ 0 - 0
docs/content/3.api/3.advanced/performance.md → docs/content/3.api/4.advanced/performance.md


+ 2 - 8
docs/content/3.api/3.advanced/primitives.md → docs/content/3.api/4.advanced/primitives.md

@@ -277,14 +277,8 @@ function onPointerLeave(event) {
 </template>
 ```
 
-### Available Events
-- `@click` - Triggered when the object is clicked
-- `@contextmenu` - Triggered on right-click
-- `@pointerdown` - Triggered when pointer is pressed down
-- `@pointerup` - Triggered when pointer is released
-- `@pointermove` - Triggered when pointer moves over the object
-- `@pointerenter` - Triggered when pointer enters the object
-- `@pointerleave` - Triggered when pointer leaves the object
+::read-more{to="/api/events/pointer-events"}
+::
 
 ## Children via Slots
 

+ 0 - 0
docs/content/3.api/3.advanced/web-gpu.md → docs/content/3.api/4.advanced/web-gpu.md


+ 4 - 4
playground/vue/src/pages/events/groups/index.vue

@@ -15,14 +15,14 @@ const handlePointerLeave = (e: PointerEvent) => {
   console.log('pointerleave', e)
 }
 
-const handlePointerMissed = (e: PointerEvent) => {
-  console.log('pointermissed', e)
+const handlePointerMissed = (event: PointerEvent) => {
+  console.log('pointermissed', event)
 }
 /* eslint-enable no-console */
 </script>
 
 <template>
-  <TresCanvas clear-color="#202020" shadows>
+  <TresCanvas clear-color="#202020" shadows @pointermissed="handlePointerMissed">
     <!-- Camera setup -->
     <TresPerspectiveCamera
       :position="[5, 5, 5]"
@@ -35,7 +35,7 @@ const handlePointerMissed = (e: PointerEvent) => {
     <TresAmbientLight :intensity="0.5" />
 
     <!-- Group of geometric shapes -->
-    <TresGroup @click="handleClick" @pointerenter="handlePointerEnter" @pointerleave="handlePointerLeave" @pointermissed="handlePointerMissed">
+    <TresGroup @click="handleClick" @pointerenter="handlePointerEnter" @pointerleave="handlePointerLeave">
       <!-- Box -->
       <TresMesh :position="[-2, 0, 0]">
         <TresBoxGeometry :args="[1, 1, 1]" />