Using Directives
Angular Three elements are like any other elements on Angular template except for they are rendered to the canvas. With that in mind, you can extend the functionality of Angular Three elements by using Directives like we do with regular elements.
The host
element
Attaching directive on the host element allows the directive instance to access to the host
via inject(ElementRef)
. Angular Three elements return the actual THREE.js object as the host element so that you can access THREE.js APIs to extend the functionality of that element.
import { Component, Directive, ElementRef, inject } from "@angular/core";import * as THREE from "three";
@Directive({ selector: "ngt-mesh[dir]" })export class MyDir { private host = inject<ElementRef<THREE.Mesh>>(ElementRef);
constructor() { this.host.nativeElement; // THREE.Mesh instance }}
@Component({ template: ` <ngt-mesh dir></ngt-mesh> `, imports: [MyDir]})export class MyCmp {}
Examples
cursor
You might have already seen this directive in action on the home page. Let’s build it here together. The key is injectObjectEvents
function from angular-three
.
@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"; }, }); } }}
Now, you can apply [cursor]
directive to any ngt-mesh
on the template.
@Component({ selector: "app-scene-graph", template: ` <ngt-mesh #mesh cursor [scale]="scale()" (pointerover)="hovered.set(true)" (pointerout)="hovered.set(false)" (click)="scale.set(scale() === 2 ? 3 : 2)" > <ngt-box-geometry /> <ngt-mesh-standard-material [color]="hovered() ? 'mediumpurple' : 'maroon'" [roughness]="0.5" [metalness]="0.5" /> </ngt-mesh>
<ngts-environment [options]="{ preset: 'warehouse' }" /> `, imports: [Cursor, NgtsEnvironment], changeDetection: ChangeDetectionStrategy.OnPush, schemas: [CUSTOM_ELEMENTS_SCHEMA],})export class SceneGraph { private meshRef = viewChild.required<ElementRef<THREE.Mesh>>("mesh");
protected hovered = signal(false); protected scale = signal(2);
constructor() { extend(THREE);
injectBeforeRender(({ delta }) => { const mesh = this.meshRef().nativeElement; mesh.rotation.x += delta; mesh.rotation.y += delta; }); }}