diff --git a/docs/api/events.md b/docs/api/events.md index c83019df8..b2e874981 100644 --- a/docs/api/events.md +++ b/docs/api/events.md @@ -6,22 +6,62 @@ ## Pointer Events +The following pointer events are available on `v3` and previous: + +- `click` +- `pointer-move` +- `pointer-enter` +- `pointer-leave` + +From `v4.x` on, the following pointer events are been added to the list: + +- `context-menu` (right click) +- `double-click` +- `pointer-down` +- `pointer-up` +- `wheel` +- `pointer-missed` + ```html ``` -| Event | fires when ... | Event Handler Parameter Type(s) | -| ------------- | ------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| click | ... the events pointerdown and pointerup fired on the same object one after the other | [Intersection](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/three/src/core/Raycaster.d.ts#L16), [PointerEvent](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent) | -| pointer-move | ... the pointer is moving above the object | [Intersection](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/three/src/core/Raycaster.d.ts#L16), [PointerEvent](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent) | -| pointer-enter | ... the pointer is entering the object | [Intersection](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/three/src/core/Raycaster.d.ts#L16), [PointerEvent](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent) | -| pointer-leave | ... the pointer is leaves the object | [PointerEvent](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent) | +|
Event
| fires when ... | Event Handler Parameter Type(s) | +| ---------------- | ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| click | the events pointerdown and pointerup fired on the same object one after the other | [Intersection](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/three/src/core/Raycaster.d.ts#L16), [PointerEvent](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent) | +| contextMenu | the user triggers a context menu, often by right-clicking | [PointerEvent](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent) | +| double-click | the user clicks the mouse button twice in quick succession on the same object | [Intersection](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/three/src/core/Raycaster.d.ts#L16), [PointerEvent](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent) | +| wheel | the mouse wheel or similar device is rotated | [WheelEvent](https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent) | +| pointer-down | the pointer is pressed down over the object | [Intersection](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/three/src/core/Raycaster.d.ts#L16), [PointerEvent](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent) | +| pointer-up | the pointer is released over the object | [Intersection](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/three/src/core/Raycaster.d.ts#L16), [PointerEvent](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent) | +| pointer-leave | the pointer is leaves the object | [PointerEvent](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent) | +| pointer-move | the pointer is moving above the object | [Intersection](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/three/src/core/Raycaster.d.ts#L16), [PointerEvent](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent) | +| pointer-missed | the pointer interaction is attempted but misses the object | [PointerEvent](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent) | + +## Event Propagation (Bubbling 🫧) + +Propagation of events on 3D scenes works differently than in the DOM because objects can **occlude each other in 3D**. The `intersections` array contains all the objects that the raycaster intersects with, sorted by distance from the camera. The first object in the array is the closest one to the camera. -The returned [Intersection](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/three/src/core/Raycaster.d.ts#L16) includes the [Object3D](https://threejs.org/docs/index.html?q=object#api/en/core/Object3D) that triggered the event. You can access it via `intersection.object`. +When an event is triggered, the event is propagated to the closest object in the `intersections` array. If the event is not handled by the object, it will be propagated to the next object in the array. -By default, objects positioned in front of others with event handlers do not prevent those events from being triggered. This behavior can be achieved by using the prop `blocks-pointer-events`. +`event.stopPropagation()` can be used to stop the event from propagating to the next object in the array, stoping the event from bubbling up and reaching to farther objects (the oens behind the first one). + +```html + +``` diff --git a/playground/components.d.ts b/playground/components.d.ts index 5a90ef3a9..ac52f4c96 100644 --- a/playground/components.d.ts +++ b/playground/components.d.ts @@ -10,6 +10,7 @@ declare module 'vue' { AkuAku: typeof import('./src/components/AkuAku.vue')['default'] AnimatedModel: typeof import('./src/components/AnimatedModel.vue')['default'] BlenderCube: typeof import('./src/components/BlenderCube.vue')['default'] + Box: typeof import('./src/components/Box.vue')['default'] CameraOperator: typeof import('./src/components/CameraOperator.vue')['default'] Cameras: typeof import('./src/components/Cameras.vue')['default'] copy: typeof import('./src/components/TheBasic copy.vue')['default'] @@ -17,6 +18,7 @@ declare module 'vue' { DebugUI: typeof import('./src/components/DebugUI.vue')['default'] DeleteMe: typeof import('./src/components/DeleteMe.vue')['default'] DynamicModel: typeof import('./src/components/DynamicModel.vue')['default'] + EventsPropogation: typeof import('./src/components/EventsPropogation.vue')['default'] FBXModels: typeof import('./src/components/FBXModels.vue')['default'] Gltf: typeof import('./src/components/gltf/index.vue')['default'] GraphPane: typeof import('./src/components/GraphPane.vue')['default'] diff --git a/playground/src/components/Box.vue b/playground/src/components/Box.vue new file mode 100644 index 000000000..02f1a097e --- /dev/null +++ b/playground/src/components/Box.vue @@ -0,0 +1,44 @@ + + + diff --git a/playground/src/pages/basic/index.vue b/playground/src/pages/basic/index.vue index daf5fea2b..1c45ce0ff 100644 --- a/playground/src/pages/basic/index.vue +++ b/playground/src/pages/basic/index.vue @@ -14,6 +14,7 @@ const state = reactive({ toneMapping: NoToneMapping, }) +const canvasRef = ref() const sphereRef = ref() const { onLoop } = useRenderLoop() @@ -21,6 +22,9 @@ const { onLoop } = useRenderLoop() onLoop(({ elapsed }) => { if (!sphereRef.value) { return } sphereRef.value.position.y += Math.sin(elapsed) * 0.01 + + // Update events without needing the mouse to move + canvasRef.value?.context?.eventManager.forceUpdate() }) function onPointerEnter(ev) { @@ -29,6 +33,10 @@ function onPointerEnter(ev) { } } +function onPointerOut(ev) { + ev.object.material.color.set('teal') +} + const sphereExists = ref(true) @@ -37,7 +45,10 @@ const sphereExists = ref(true) v-model="sphereExists" type="checkbox" /> - + diff --git a/playground/src/pages/events/Propagation.vue b/playground/src/pages/events/Propagation.vue new file mode 100644 index 000000000..a9847cf7a --- /dev/null +++ b/playground/src/pages/events/Propagation.vue @@ -0,0 +1,188 @@ + + + diff --git a/playground/src/pages/events/index.vue b/playground/src/pages/events/index.vue index 773e4f764..08a145879 100644 --- a/playground/src/pages/events/index.vue +++ b/playground/src/pages/events/index.vue @@ -1,8 +1,11 @@ +