Object Events
Object Events is an API that allows you to forward pointer events to a THREE.js object, usually in a custom abstractions.
Usage
There are 2 ways to use Object Events API.
injectObjectEvents
This is a more direct way to use the API. It is useful for cases where you control the events you want to forward to the underlying THREE.js object, like in using directives guide.
@Directive({ selector: "ngt-mesh[cursor]" })export class Cursor { constructor() { const document = inject(DOCUMENT); const elementRef = inject<ElementRef<THREE.Mesh>>(ElementRef); const nativeElement = elementRef.nativeElement;
if (nativeElement.isMesh) { injectObjectEvents(() => nativeElement, { pointerover: () => { document.body.style.cursor = "pointer"; }, pointerout: () => { document.body.style.cursor = "default"; }, }); } }}
Then all <ngt-mesh cursor>
will have pointerover
and pointerout
events forwarded to the underlying THREE.Mesh
object.
NgtObjectEvents
This is intended to be used as a hostDirectives
on a custom abstraction. This is useful for cases where you don’t know which events the abstraction’s consumers will use. NgtObjectEvents
calls injectObjectEvents
internally.
@Component({ selector: 'app-my-mesh', template: ` <ngt-mesh #mesh> <!-- mesh contents --> </ngt-mesh> `, hostDirectives: [{ directive: NgtObjectEvents, outputs: [ 'click', 'pointerover', 'pointerout', // ... other events you want to expose ] }]})export class MyMesh { private meshRef = viewChild.required<ElementRef<THREE.Mesh>>('mesh');
constructor() { const objectEvents = inject(NgtObjectEvents, { host: true }); objectEvents.ngtObjectEvents.set(this.meshRef); }}
ngtObjectEvents
is a Model Input that can accept:
- an
ElementRef<THREE.Object3D>
- a
THREE.Object3D
- a
Signal<ElementRef<THREE.Object3D> | THREE.Object3D>
How it works
When using injetObjectEvents
:
- It takes a target function that returns the object to attach events to
- Event handlers are registered using
Renderer2
- Event cleanup is handled automatically through
DestroyRef
- Returns an array of cleanup functions if manual cleanup is needed
Example: GLTF Model with Events
@Component({ selector: 'app-astronaut', template: ` @if (gltf(); as gltf) { <ngt-group #model [parameters]="options()"> <ngt-mesh receiveShadow castShadow [geometry]="gltf.nodes.Astronaut_mesh.geometry" [material]="gltf.materials.Astronaut_mat" /> </ngt-group> } `, hostDirectives: [{ directive: NgtObjectEvents, outputs: ['click', 'pointerover', 'pointerout'] }]})export class Astronaut { modelRef = viewChild<ElementRef<Group>>('model');
constructor() { const objectEvents = inject(NgtObjectEvents, { host: true }); effect(() => { const model = this.modelRef()?.nativeElement; if (!model) return; objectEvents.ngtObjectEvents.set(model); }); }}
Now consumers can use the Astronaut
component with event handling
<app-astronaut (click)="onAstronautClick($event)" (pointerover)="onAstronautHover($event)"/>