Skip to content

Commit 016dbf3

Browse files
committed
docs: adjust routed rocks and add more docs about portals
1 parent e816059 commit 016dbf3

File tree

5 files changed

+208
-3
lines changed

5 files changed

+208
-3
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { NgTemplateOutlet } from '@angular/common';
2+
import { ChangeDetectionStrategy, Component, CUSTOM_ELEMENTS_SCHEMA, ElementRef, viewChild } from '@angular/core';
3+
import { extend, injectBeforeRender, NgtCanvas } from 'angular-three';
4+
import { NgtsGrid } from 'angular-three-soba/abstractions';
5+
import { NgtsPerspectiveCamera } from 'angular-three-soba/cameras';
6+
import { NgtsOrbitControls } from 'angular-three-soba/controls';
7+
import * as THREE from 'three';
8+
import { DEG2RAD } from 'three/src/math/MathUtils.js';
9+
10+
extend(THREE);
11+
12+
@Component({
13+
template: `
14+
<ngts-perspective-camera [options]="{ makeDefault: true, position: [10, 10, 10], fov: 30 }" />
15+
<ngts-orbit-controls
16+
[options]="{
17+
enableZoom: false,
18+
maxPolarAngle: 85 * DEG2RAD,
19+
minPolarAngle: 20 * DEG2RAD,
20+
maxAzimuthAngle: 45 * DEG2RAD,
21+
minAzimuthAngle: -45 * DEG2RAD,
22+
}"
23+
/>
24+
25+
<ngts-grid
26+
[options]="{
27+
planeArgs: [10.5, 10.5],
28+
position: [0, -0.01, 0],
29+
cellSize: 0.6,
30+
cellThickness: 1,
31+
cellColor: '#6f6f6f',
32+
sectionSize: 3.3,
33+
sectionThickness: 1.5,
34+
sectionColor: '#9d4b4b',
35+
fadeDistance: 25,
36+
fadeStrength: 1,
37+
followCamera: false,
38+
infiniteGrid: true,
39+
}"
40+
/>
41+
42+
<ngt-directional-light [position]="[5, 10, 3]" />
43+
44+
<ngt-object3D #trail [position]="[0, 0.5, 0]">
45+
<ng-container [ngTemplateOutlet]="forTrail" />
46+
</ngt-object3D>
47+
48+
<ng-template #forTrail>
49+
<ng-container [ngTemplateOutlet]="mesh" [ngTemplateOutletContext]="{ color: '#fe3d00' }" />
50+
<ngt-group [position]="[0, 1, 0]">
51+
<ng-container [ngTemplateOutlet]="mesh" [ngTemplateOutletContext]="{ color: '#2f7dc6' }" />
52+
</ngt-group>
53+
</ng-template>
54+
55+
<ng-template #mesh let-color="color">
56+
<ngt-mesh>
57+
<ngt-box-geometry />
58+
<ngt-mesh-standard-material [color]="color" />
59+
</ngt-mesh>
60+
</ng-template>
61+
`,
62+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
63+
changeDetection: ChangeDetectionStrategy.OnPush,
64+
imports: [NgtsOrbitControls, NgtsPerspectiveCamera, NgtsGrid, NgTemplateOutlet],
65+
host: { class: 'template-outlet-experience' },
66+
})
67+
export class Experience {
68+
protected readonly DEG2RAD = DEG2RAD;
69+
70+
private trailRef = viewChild.required<ElementRef<THREE.Object3D>>('trail');
71+
72+
constructor() {
73+
injectBeforeRender(() => {
74+
const obj = this.trailRef().nativeElement;
75+
obj.position.x = Math.sin(Date.now() / 1000) * 4;
76+
});
77+
}
78+
}
79+
80+
@Component({
81+
template: `
82+
<ngt-canvas [sceneGraph]="scene" />
83+
`,
84+
imports: [NgtCanvas],
85+
changeDetection: ChangeDetectionStrategy.OnPush,
86+
host: { class: 'template-outlet-docs' },
87+
})
88+
export default class TemplateOutletScene {
89+
scene = Experience;
90+
}

Diff for: apps/astro-docs/src/content/docs/core/advanced/portals.mdx

+90-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,93 @@
11
---
22
title: Portals
3-
description: Details about the Angular Three `NgtPortal`
3+
description: Details about the Angular Three ways of handling "portals"
44
---
55

6+
import { Tabs, TabItem, Code } from '@astrojs/starlight/components';
7+
import TemplateOutletScene, {
8+
content as templateOutletContent,
9+
} from '../../../../components/template-outlet/template-outlet?includeContent';
10+
11+
Portals might have different meaning depending on the use-cases. In general,
12+
it means that we want to render something as children of something else without following
13+
the hierarchy of the template. Pseudo-code looks something like this:
14+
15+
```html
16+
<ngt-group>
17+
<!-- render ngt-mesh here -->
18+
</ngt-group>
19+
20+
<!-- outside of the hierarchy -->
21+
<ngt-mesh></ngt-mesh>
22+
```
23+
24+
## `NgTemplateOutlet`
25+
26+
For many cases, we can use `NgTemplateOutlet` if we just want to _portal_ objects around with (or without) different context data. In other words, we can
27+
use this technique to _reuse_ templates.
28+
29+
<Tabs>
30+
<TabItem label="Preview">
31+
<div class="h-96 w-full border border-dashed border-accent-500 rounded">
32+
<TemplateOutletScene client:only />
33+
</div>
34+
</TabItem>
35+
<TabItem label="Code">
36+
<Code code={templateOutletContent} lang="angular-ts" />
37+
</TabItem>
38+
</Tabs>
39+
40+
What we're seeing here is:
41+
42+
- An `Object3D` that is being moved back and forth
43+
- A `Mesh` as a child of the `Object3D`
44+
- A `Group`
45+
- Another `Mesh` as a child of the `Group`
46+
47+
The main takeaway here is that this `Mesh` is being _reused_ and has different color based on where it's rendered.
48+
49+
```angular-html
50+
<ngt-object3D>
51+
<ng-container [ngTemplateOutlet]="forObject3D" />
52+
</ngt-object3D>
53+
54+
<ng-template #forObject3D>
55+
<ng-container [ngTemplateOutlet]="mesh" [ngTemplateOutletContext]="{ color: '#fe3d00' }" />
56+
<ngt-group [position]="[0, 1, 0]">
57+
<ng-container [ngTemplateOutlet]="mesh" [ngTemplateOutletContext]="{ color: '#2f7dc6' }" />
58+
</ngt-group>
59+
</ng-template>
60+
61+
<ng-template #mesh let-color="color">
62+
<ngt-mesh>
63+
<ngt-box-geometry />
64+
<ngt-mesh-standard-material [color]="color" />
65+
</ngt-mesh>
66+
</ng-template>
67+
```
68+
69+
## `NgtParent`
70+
71+
This technique is useful for when you _cannot_ control the template for, well, **ng-template**.
72+
For example, routed components via [`ngt-router-outlet`](./routed-scene#custom-routed-scene)
73+
74+
`NgtParent` is a structural directive and it takes an input `parent`. `parent` accepts
75+
76+
- A `string`: which will be used to look up the object with `getObjectByName()`
77+
- An `Object3D`
78+
- An `ElementRef<Object3D>`
79+
- or a `Signal` of all of these above
80+
81+
Attaching `*parent` on an element will _portal_ that element as a child to the `parent` input.
82+
83+
:::tip[Did you know?]
84+
85+
Check out the [Routed Rocks example](https://demo.angularthree.org/routed-rocks)
86+
87+
:::
88+
89+
## `NgtPortal`
90+
691
In THREE.js, there is a construct called `WebGLRenderTarget`. It is used to render the scene into a texture and then
792
render the texture into the canvas. This is useful for things like post-processing effects, or HUD-like visuals.
893

@@ -49,6 +134,8 @@ over `THREE.PerspectiveCamera` that has the ability to make itself the default c
49134

50135
:::
51136

52-
## Examples
137+
:::tip[Did you know?]
138+
139+
Check out [HUD example](/blog/v2#heads-up-display-example)
53140

54-
TBD
141+
:::

Diff for: apps/kitchen-sink/src/app/routed-rocks/colored-rock.ts

+19
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,23 @@ export default class ColoredRock {
5858

5959
private rockStore = inject(RockStore);
6060
protected readonly selectedRock = this.rockStore.selectedRock;
61+
62+
constructor() {
63+
// NOTE: we can use ng-template for this use-case as well.
64+
// Just a little more involved than `NgtParent`
65+
//
66+
// effect(() => {
67+
// const colorId = this.colorId();
68+
// if (!colorId) return;
69+
//
70+
// const templateRef = this.templateRef();
71+
// this.rockStore.coloredRockTemplateRefs.set({
72+
// [colorId]: templateRef,
73+
// });
74+
// });
75+
//
76+
// inject(DestroyRef).onDestroy(() => {
77+
// this.rockStore.coloredRockTemplateRefs.set({});
78+
// });
79+
}
6180
}

Diff for: apps/kitchen-sink/src/app/routed-rocks/constants.ts

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const colors = [
2828

2929
export const menus = colors.map((color, index) => ({
3030
id: index + 1,
31+
slug: color.slug,
3132
label: color.label,
3233
name: `rock-${color.slug}`,
3334
path: `/routed-rocks/rocks/${color.slug}`,

Diff for: apps/kitchen-sink/src/app/routed-rocks/rocks.ts

+8
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ interface RockGLTF extends GLTF {
6767
(click)="router.navigate([menu.path])"
6868
>
6969
<ngt-mesh-phong-material [color]="menu.color" [side]="FrontSide" />
70+
71+
<!-- NOTE: we can use ng-template for this use-case as well. -->
72+
<!-- @let templateRefs = coloredRockTemplateRefs(); -->
73+
<!-- @let template = templateRefs[menu.slug]; -->
74+
<!---->
75+
<!-- @if (template) { -->
76+
<!-- <ng-container [ngTemplateOutlet]="template" [ngTemplateOutletContext]="{ $implicit: menu }" /> -->
77+
<!-- } -->
7078
</ngt-mesh>
7179
</ngt-group>
7280
}

0 commit comments

Comments
 (0)