Store
Angular Three store utilizes ngrx/signals
, specifically SignalState
, as the implementation details.
NgtCanvas
component from each platform provides the default store which has the type of SignalState<NgtState>
. Store can be layered, or linked, by component like NgtPortal
or components that make use of NgtPortal
.
export interface NgtState { /** id **/ id: string; /** The instance of the renderer */ gl: THREE.WebGLRenderer; /** Default camera */ camera: NgtCamera; /** Default scene */ scene: THREE.Scene; /** Default raycaster */ raycaster: THREE.Raycaster; /** Default clock */ clock: THREE.Clock; /** Event layer interface, contains the event handler and the node they're connected to */ events: NgtEventManager<any>; /** XR interface */ xr: NgtXRManager; /** Currently used controls */ controls: THREE.EventDispatcher | null; /** Normalized event coordinates */ pointer: THREE.Vector2; /* Whether to enable r139's ColorManagement */ legacy: boolean; /** Shortcut to gl.outputColorSpace = LinearSRGBColorSpace */ linear: boolean; /** Shortcut to gl.toneMapping = NoTonemapping */ flat: boolean; /** Render loop flags */ frameloop: NgtFrameloop; /** Adaptive performance interface */ performance: NgtPerformance; /** Reactive pixel-size of the canvas */ size: NgtSize; /** Reactive size of the viewport in threejs units */ viewport: NgtViewport & { getCurrentViewport: ( camera: NgtCamera, target?: THREE.Vector3 | Parameters<THREE.Vector3['set']>, size?: NgtSize, ) => Omit<NgtViewport, 'dpr' | 'initialDpr'>; }; /** Flags the canvas for render, but doesn't render in itself */ invalidate: (frames?: number) => void; /** Advance (render) one step */ advance: (timestamp: number, runGlobalEffects?: boolean) => void; /** Shortcut to setting the event layer */ setEvents: (events: Partial<NgtEventManager<any>>) => void; /** * Shortcut to manual sizing */ setSize: (width: number, height: number, top?: number, left?: number) => void; /** Shortcut to manual setting the pixel ratio */ setDpr: (dpr: NgtDpr) => void; /** Shortcut to frameloop flags */ setFrameloop: (frameloop?: NgtFrameloop) => void; /** When the canvas was clicked but nothing was hit */ /** PointerMissed Observable */ pointerMissed$: Observable<MouseEvent>; /** If this state model is layered (via createPortal) then this contains the previous layer */ previousRoot: SignalState<NgtState> | null; /** Internals */ internal: NgtInternalState;}
injectStore()
To gain access to the store of the current context, either the root/default one or a layered one, you can call injectStore()
. injectStore()
accepts InjectOptions
so you can control how DI works for injectStore()
.
export class MyCmp { constructor() { const store = injectStore(); // SignalState<NgtState> }}
Accessing reactive state
By implementing SignalState
, Store is deeply reactive (via Proxy
).
You can access any piece of the state by using dot-separated path.
export class MyCmp { constructor() { const store = injectStore(); store.gl(); // Signal<THREE.WebGLRenderer> store.size(); // Signal<NgtSize> store.size.width(); // Signal<number> }}
Accessing snapshot state
In situations like inside of injectBeforeRender
body where whether tracking/reading a Signal does not matter, you can access the snapshot state instead via store.snapshot
export class MyCmp { constructor() { const store = injectStore(); injectBeforeRender(() => { // because beforeRender body runs on every frame, it does not matter whether we read signal value or not
store.snapshot.camera; // NgtCamera store.snapshot.invalidate(); // call invalidate() }) }}