Skip to content

Commit a839320

Browse files
committed
feat: event handling registration from localState of nodes
1 parent 5bd10da commit a839320

File tree

6 files changed

+58
-56
lines changed

6 files changed

+58
-56
lines changed

playground/src/components/TheExperience.vue

+1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ watchEffect(() => {
7070
:rotation="[-Math.PI / 2, 0, Math.PI / 2]"
7171
name="floor"
7272
receive-shadow
73+
@click="wireframe = !wireframe"
7374
>
7475
<TresPlaneGeometry :args="[20, 20, 20]" />
7576
<TresMeshToonMaterial

src/components/TresCanvas.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ onMounted(() => {
139139
emit,
140140
})
141141
142-
usePointerEventHandler({ scene: scene.value, contextParts: context.value })
142+
usePointerEventHandler(context.value)
143143
144144
const { registerCamera, camera, cameras, deregisterCamera } = context.value
145145

src/composables/usePointerEventHandler/index.ts

+10-14
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import type { Intersection, Object3D, Object3DEventMap } from 'three'
2-
import type { TresScene } from 'src/types'
32
import { computed, reactive, ref } from 'vue'
43
import { uniqueBy } from '../../utils'
54
import { useRaycaster } from '../useRaycaster'
@@ -17,11 +16,7 @@ export interface EventProps {
1716
}
1817

1918
export const usePointerEventHandler = (
20-
{ scene, contextParts }:
21-
{
22-
scene: TresScene
23-
contextParts: Pick<TresContext, 'renderer' | 'camera' | 'raycaster'>
24-
},
19+
ctx: TresContext,
2520
) => {
2621
const objectsWithEventListeners = reactive({
2722
click: new Map<Object3D<Object3DEventMap>, CallbackFn>(),
@@ -54,13 +49,6 @@ export const usePointerEventHandler = (
5449
if (onPointerLeave) objectsWithEventListeners.pointerLeave.set(object, onPointerLeave)
5550
}
5651

57-
// to make the registerObject available in the custom renderer (nodeOps), it is attached to the scene
58-
scene.userData.tres__registerAtPointerEventHandler = registerObject
59-
scene.userData.tres__deregisterAtPointerEventHandler = deregisterObject
60-
61-
scene.userData.tres__registerBlockingObjectAtPointerEventHandler = registerBlockingObject
62-
scene.userData.tres__deregisterBlockingObjectAtPointerEventHandler = deregisterBlockingObject
63-
6452
const objectsToWatch = computed(() =>
6553
uniqueBy(
6654
[
@@ -73,7 +61,13 @@ export const usePointerEventHandler = (
7361
),
7462
)
7563

76-
const { onClick, onPointerMove } = useRaycaster(objectsToWatch, contextParts)
64+
// Temporaly add the methods to the context, this should be handled later by the EventManager state on the context https://github.com/Tresjs/tres/issues/515
65+
ctx.registerObjectAtPointerEventHandler = registerObject
66+
ctx.deregisterObjectAtPointerEventHandler = deregisterObject
67+
ctx.registerBlockingObjectAtPointerEventHandler = registerBlockingObject
68+
ctx.deregisterBlockingObjectAtPointerEventHandler = deregisterBlockingObject
69+
70+
const { onClick, onPointerMove } = useRaycaster(objectsToWatch, ctx)
7771

7872
onClick(({ intersects, event }) => {
7973
if (intersects.length) objectsWithEventListeners.click.get(intersects[0].object)?.(intersects[0], event)
@@ -101,5 +95,7 @@ export const usePointerEventHandler = (
10195
return {
10296
registerObject,
10397
deregisterObject,
98+
registerBlockingObject,
99+
deregisterBlockingObject,
104100
}
105101
}

src/composables/useRaycaster/index.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,10 @@ interface PointerClickEventPayload {
2020

2121
export const useRaycaster = (
2222
objects: Ref<THREE.Object3D[]>,
23-
{ renderer, camera, raycaster }: Pick<TresContext, 'renderer' | 'camera' | 'raycaster'>,
23+
ctx: TresContext,
2424
) => {
2525
// having a separate computed makes useElementBounding work
26-
const canvas = computed(() => renderer.value.domElement as HTMLCanvasElement)
26+
const canvas = computed(() => ctx.renderer.value.domElement as HTMLCanvasElement)
2727

2828
const { x, y } = usePointer({ target: canvas })
2929

@@ -39,11 +39,11 @@ export const useRaycaster = (
3939
}
4040

4141
const getIntersectsByRelativePointerPosition = ({ x, y }: { x: number; y: number }) => {
42-
if (!camera.value) return
42+
if (!ctx.camera.value) return
4343

44-
raycaster.value.setFromCamera(new Vector2(x, y), camera.value)
44+
ctx.raycaster.value.setFromCamera(new Vector2(x, y), ctx.camera.value)
4545

46-
return raycaster.value.intersectObjects(objects.value, false)
46+
return ctx.raycaster.value.intersectObjects(objects.value, false)
4747
}
4848

4949
const getIntersects = (event?: PointerEvent | MouseEvent) => {

src/composables/useTresContextProvider/index.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { toValue, useElementSize, useFps, useMemory, useRafFn, useWindowSize, refDebounced } from '@vueuse/core'
22
import { inject, provide, readonly, shallowRef, computed, ref, onUnmounted, watchEffect } from 'vue'
3-
import type { Camera, EventDispatcher, WebGLRenderer } from 'three'
3+
import type { Camera, EventDispatcher, Object3D, WebGLRenderer } from 'three'
44
import { Raycaster } from 'three'
55
import type { ComputedRef, DeepReadonly, MaybeRef, MaybeRefOrGetter, Ref, ShallowRef } from 'vue'
66
import { calculateMemoryUsage } from '../../utils/perf'
@@ -10,6 +10,7 @@ import { useRenderer } from '../useRenderer'
1010
import { extend } from '../../core/catalogue'
1111
import { useLogger } from '../useLogger'
1212
import type { TresScene } from '../../types'
13+
import type { EventProps } from '../usePointerEventHandler'
1314

1415
export interface InternalState {
1516
priority: Ref<number>
@@ -62,9 +63,17 @@ export interface TresContext {
6263
* Advance one frame when renderMode === 'manual'
6364
*/
6465
advance: () => void
66+
// Camera
6567
registerCamera: (camera: Camera) => void
6668
setCameraActive: (cameraOrUuid: Camera | string) => void
6769
deregisterCamera: (camera: Camera) => void
70+
// Events
71+
// Temporaly add the methods to the context, this should be handled later by the EventManager state on the context https://github.com/Tresjs/tres/issues/515
72+
// When thats done maybe we can short the names of the methods since the parent will give the context.
73+
registerObjectAtPointerEventHandler: (object: Object3D & EventProps) => void
74+
deregisterObjectAtPointerEventHandler: (object: Object3D) => void
75+
registerBlockingObjectAtPointerEventHandler: (object: Object3D) => void
76+
deregisterBlockingObjectAtPointerEventHandler: (object: Object3D) => void
6877
}
6978

7079
export function useTresContextProvider({

src/core/nodeOps.ts

+31-35
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import type { Object3D, Camera } from 'three'
55
import type { TresContext } from '../composables'
66
import { useLogger } from '../composables'
77
import { deepArrayEqual, isHTMLTag, kebabToCamel } from '../utils'
8-
98
import type { TresObject, TresObject3D, TresScene } from '../types'
109
import { catalogue } from './catalogue'
1110

@@ -95,28 +94,27 @@ export const nodeOps: RendererOptions<TresObject, TresObject | null> = {
9594
return instance as TresObject
9695
},
9796
insert(child, parent) {
97+
if (!child) return
98+
9899
if (parent && parent.isScene) {
99100
scene = parent as unknown as TresScene
100-
if (child) {
101-
child.__tres.root = scene.__tres.root as TresContext
102-
}
103101
}
104102

105-
const parentObject = parent || scene
103+
if (scene) {
104+
child.__tres.root = scene.__tres.root as TresContext
105+
}
106106

107+
const parentObject = parent || scene
108+
107109
if (child?.isObject3D) {
108-
110+
const { registerCamera, registerObjectAtPointerEventHandler } = child.__tres.root
109111
if (child?.isCamera) {
110-
child.__tres.root.registerCamera?.(child as unknown as Camera)
112+
registerCamera(child as unknown as Camera)
111113
}
112-
113114
if (
114115
child && supportedPointerEvents.some(eventName => child[eventName])
115116
) {
116-
if (!scene?.userData.tres__registerAtPointerEventHandler)
117-
throw 'could not find tres__registerAtPointerEventHandler on scene\'s userData'
118-
119-
scene?.userData.tres__registerAtPointerEventHandler?.(child as Object3D)
117+
registerObjectAtPointerEventHandler(child as Object3D)
120118
}
121119
}
122120

@@ -137,6 +135,10 @@ export const nodeOps: RendererOptions<TresObject, TresObject | null> = {
137135
remove(node) {
138136
if (!node) return
139137
// remove is only called on the node being removed and not on child nodes.
138+
const {
139+
deregisterObjectAtPointerEventHandler,
140+
deregisterBlockingObjectAtPointerEventHandler,
141+
} = node.__tres.root
140142

141143
if (node.isObject3D) {
142144
const object3D = node as unknown as Object3D
@@ -155,37 +157,23 @@ export const nodeOps: RendererOptions<TresObject, TresObject | null> = {
155157
}
156158
}
157159

158-
const deregisterAtPointerEventHandler = scene?.userData.tres__deregisterAtPointerEventHandler
159-
const deregisterBlockingObjectAtPointerEventHandler
160-
= scene?.userData.tres__deregisterBlockingObjectAtPointerEventHandler
161-
162160
const deregisterAtPointerEventHandlerIfRequired = (object: TresObject) => {
163-
164-
if (!deregisterBlockingObjectAtPointerEventHandler)
165-
throw 'could not find tres__deregisterBlockingObjectAtPointerEventHandler on scene\'s userData'
166-
167-
scene?.userData.tres__deregisterBlockingObjectAtPointerEventHandler?.(object as Object3D)
168-
169-
if (!deregisterAtPointerEventHandler)
170-
throw 'could not find tres__deregisterAtPointerEventHandler on scene\'s userData'
171-
161+
deregisterBlockingObjectAtPointerEventHandler(object as Object3D)
172162
if (
173163
object && supportedPointerEvents.some(eventName => object[eventName])
174164
)
175-
deregisterAtPointerEventHandler?.(object as Object3D)
165+
deregisterObjectAtPointerEventHandler?.(object as Object3D)
176166
}
177167

178168
const deregisterCameraIfRequired = (object: Object3D) => {
179169
const deregisterCamera = node.__tres.root.deregisterCamera
180170

181-
if (!deregisterCamera)
182-
throw 'could not find tres__deregisterCamera on scene\'s userData'
183-
184171
if ((object as Camera).isCamera)
185172
deregisterCamera?.(object as Camera)
186173
}
187174

188175
node.removeFromParent?.()
176+
189177
object3D.traverse((child: Object3D) => {
190178
disposeMaterialsAndGeometries(child)
191179
deregisterCameraIfRequired(child)
@@ -204,13 +192,21 @@ export const nodeOps: RendererOptions<TresObject, TresObject | null> = {
204192
if (node) {
205193
let root = node
206194
let key = prop
207-
if (node.isObject3D && key === 'blocks-pointer-events') {
208-
if (nextValue || nextValue === '')
209-
scene?.userData.tres__registerBlockingObjectAtPointerEventHandler?.(node as Object3D)
210-
else
211-
scene?.userData.tres__deregisterBlockingObjectAtPointerEventHandler?.(node as Object3D)
212195

213-
return
196+
if (node.__tres.root) {
197+
const {
198+
registerBlockingObjectAtPointerEventHandler,
199+
deregisterBlockingObjectAtPointerEventHandler,
200+
} = node.__tres.root
201+
202+
if (node.isObject3D && key === 'blocks-pointer-events') {
203+
if (nextValue || nextValue === '')
204+
registerBlockingObjectAtPointerEventHandler(node as Object3D)
205+
else
206+
deregisterBlockingObjectAtPointerEventHandler(node as Object3D)
207+
208+
return
209+
}
214210
}
215211

216212
let finalKey = kebabToCamel(key)

0 commit comments

Comments
 (0)