Skip to content

Commit 50512c4

Browse files
committed
docs(examples): update misc routes
1 parent d7eb6d3 commit 50512c4

File tree

7 files changed

+261
-116
lines changed

7 files changed

+261
-116
lines changed
Lines changed: 81 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,89 @@
1-
import { Component } from '@angular/core';
2-
import { RouterOutlet } from '@angular/router';
1+
import { Component, computed, inject } from '@angular/core';
2+
import { toSignal } from '@angular/core/rxjs-interop';
3+
import { ActivationEnd, NavigationEnd, Router, RouterOutlet } from '@angular/router';
4+
import { filter } from 'rxjs';
35

46
@Component({
57
selector: 'app-root',
68
template: `
79
<router-outlet />
10+
11+
<div class="absolute bottom-4 right-4 flex gap-4 items-center">
12+
<select [value]="currentRoute()" (change)="onChange($event)">
13+
<option value="soba">/soba</option>
14+
<option value="cannon">/cannon</option>
15+
<option value="postprocessing">/postprocessing</option>
16+
<option value="rapier">/rapier</option>
17+
<option value="misc">/misc</option>
18+
<option value="routed">/routed</option>
19+
<option value="routed-rocks">/routed-rocks</option>
20+
</select>
21+
22+
<div class="bg-white rounded-full p-2 text-black border border-white border-dashed">
23+
<a class="cursor-pointer" [href]="currentSourcePath()" target="_blank" title="View source">
24+
<svg
25+
xmlns="http://www.w3.org/2000/svg"
26+
fill="none"
27+
viewBox="0 0 24 24"
28+
stroke-width="1.5"
29+
stroke="currentColor"
30+
class="h-6 w-6"
31+
>
32+
<path
33+
stroke-linecap="round"
34+
stroke-linejoin="round"
35+
d="M17.25 6.75 22.5 12l-5.25 5.25m-10.5 0L1.5 12l5.25-5.25m7.5-3-4.5 16.5"
36+
/>
37+
</svg>
38+
</a>
39+
</div>
40+
</div>
41+
42+
@if (currentActivatedRouteCredits(); as credits) {
43+
<div class="absolute top-2 right-2 font-mono" [class]="credits.class">
44+
Credits:
45+
<a class="underline" [href]="credits.link" target="_blank" rel="noreferrer">{{ credits.title }}</a>
46+
</div>
47+
}
848
`,
949
imports: [RouterOutlet],
1050
})
11-
export class AppComponent {}
12-
13-
// <div class="absolute bottom-4 right-4 flex gap-4 items-center">
14-
// <select [value]="currentRoute()" (change)="onChange($event)">
15-
// <option value="soba">/soba</option>
16-
// <option value="cannon">/cannon</option>
17-
// <option value="postprocessing">/postprocessing</option>
18-
// <option value="rapier">/rapier</option>
19-
// <option value="misc">/misc</option>
20-
// <option value="routed">/routed</option>
21-
// <option value="routed-rocks">/routed-rocks</option>
22-
// </select>
23-
//
24-
// <div class="bg-white rounded-full p-2 text-black border border-white border-dashed">
25-
// <a class="cursor-pointer" [href]="currentSourcePath()" target="_blank" title="View source">
26-
// <svg
27-
// xmlns="http://www.w3.org/2000/svg"
28-
// fill="none"
29-
// viewBox="0 0 24 24"
30-
// stroke-width="1.5"
31-
// stroke="currentColor"
32-
// class="h-6 w-6"
33-
// >
34-
// <path
35-
// stroke-linecap="round"
36-
// stroke-linejoin="round"
37-
// d="M17.25 6.75 22.5 12l-5.25 5.25m-10.5 0L1.5 12l5.25-5.25m7.5-3-4.5 16.5"
38-
// />
39-
// </svg>
40-
// </a>
41-
// </div>
42-
// </div>
43-
//
44-
// @if (currentActivatedRouteCredits(); as credits) {
45-
// <div class="absolute top-2 right-2 font-mono" [class]="credits.class">
46-
// Credits:
47-
// <a class="underline" [href]="credits.link" target="_blank" rel="noreferrer">{{ credits.title }}</a>
48-
// </div>
49-
// }
51+
export class AppComponent {
52+
private router = inject(Router);
53+
54+
private navigationEnd = toSignal(this.router.events.pipe(filter((event) => event instanceof NavigationEnd)));
55+
private activationEnd = toSignal(this.router.events.pipe(filter((event) => event instanceof ActivationEnd)));
56+
57+
protected currentRoute = computed(() => {
58+
const navigationEnd = this.navigationEnd();
59+
if (!navigationEnd) return 'soba';
60+
const [segment] = navigationEnd.urlAfterRedirects.split('/').filter(Boolean);
61+
return segment;
62+
});
63+
64+
protected currentSourcePath = computed(() => {
65+
const navigationEnd = this.navigationEnd();
66+
if (!navigationEnd) return '';
67+
const paths = navigationEnd.urlAfterRedirects.split('/').filter(Boolean);
68+
return `https://github.com/angular-threejs/angular-three/tree/main/apps/kitchen-sink/src/app/${paths.join('/')}`;
69+
});
70+
71+
protected currentActivatedRouteCredits = computed(() => {
72+
const activationEnd = this.activationEnd();
73+
if (!activationEnd) return null;
74+
75+
let deepestChild = activationEnd.snapshot;
76+
while (deepestChild && deepestChild.firstChild) {
77+
deepestChild = deepestChild.firstChild;
78+
}
79+
80+
if (!deepestChild) return null;
81+
82+
return deepestChild.data['credits'] as { title: string; link: string; class: string };
83+
});
84+
85+
protected onChange(event: Event) {
86+
const target = event.target as HTMLSelectElement;
87+
void this.router.navigate([target.value]);
88+
}
89+
}

apps/kitchen-sink-new/src/app/misc/basic/scene.ts

Lines changed: 78 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import {
2-
Attribute,
32
ChangeDetectionStrategy,
43
Component,
54
CUSTOM_ELEMENTS_SCHEMA,
65
ElementRef,
6+
HostAttributeToken,
7+
inject,
78
input,
89
signal,
910
viewChild,
@@ -57,8 +58,9 @@ export class Box {
5758
position = input<NgtVector3>(0);
5859
color = input('turquoise');
5960

60-
constructor(@Attribute('context') context: string) {
61+
constructor() {
6162
const store = injectStore();
63+
const context = inject(new HostAttributeToken('context'), { optional: true });
6264
console.log({ context, store: store.snapshot.id, previous: store.snapshot.previousRoot });
6365
}
6466

@@ -97,6 +99,8 @@ export class NestedBox {
9799
@Component({
98100
selector: 'app-scene',
99101
template: `
102+
<ngt-color attach="background" *args="['#303030']" />
103+
100104
<ngt-ambient-light [intensity]="Math.PI" />
101105
<ngt-directional-light [position]="5" [intensity]="Math.PI" />
102106
@@ -109,81 +113,81 @@ export class NestedBox {
109113
110114
<ngt-primitive *args="[mesh]" [parameters]="{ position: [2, 0, 0] }" />
111115
112-
<!-- <app-nested-box [position]="[-3, 0, 0]" />-->
113-
114-
<!-- &lt;!&ndash; three element under condition &ndash;&gt;-->
115-
<!-- @if (show()) {-->
116-
<!-- <ngt-mesh [position]="[3, 0, 0]">-->
117-
<!-- <ngt-icosahedron-geometry />-->
118-
<!-- <ngt-mesh-normal-material />-->
119-
<!-- </ngt-mesh>-->
120-
<!-- }-->
121-
122-
<!-- &lt;!&ndash; component wrapping three elemnent &ndash;&gt;-->
123-
<!-- <app-box [position]="[1, 0, 0]" />-->
124-
125-
<!-- &lt;!&ndash; with input for default content &ndash;&gt;-->
126-
<!-- <app-box [position]="[-1, 0, 0]" color="red" />-->
127-
128-
<!-- &lt;!&ndash; with custom ng content &ndash;&gt;-->
129-
<!-- <app-box [position]="[0, 1, 0]">-->
130-
<!-- <ngt-mesh-standard-material color="green" />-->
131-
<!-- </app-box>-->
132-
133-
<!-- &lt;!&ndash; with property binding for input for default content &ndash;&gt;-->
134-
<!-- <app-box [position]="[0, -1, 0]" [color]="color()" />-->
135-
136-
<!-- &lt;!&ndash; component under condition &ndash;&gt;-->
137-
<!-- @if (show()) {-->
138-
<!-- <app-box [position]="[1, 1, 0]">-->
139-
<!-- @if (show()) {-->
140-
<!-- <ngt-mesh-phong-material color="yellow" />-->
141-
<!-- }-->
142-
<!-- </app-box>-->
143-
<!-- }-->
144-
145-
<!-- &lt;!&ndash; component with component as content &ndash;&gt;-->
146-
<!-- <app-box [position]="[-1, -1, 0]" color="brown" context="in root">-->
147-
<!-- <app-box data-children [position]="[-0.5, -0.5, 0]" color="pink" context="in box content in root" />-->
148-
<!-- </app-box>-->
149-
150-
<!-- &lt;!&ndash; component with both content projection slots &ndash;&gt;-->
151-
<!-- <app-box [position]="[-1, 1, 0]">-->
152-
<!-- <ngt-mesh-lambert-material color="orange" />-->
153-
<!-- <app-box data-children [position]="[-0.5, 0.5, 0]" color="skyblue" />-->
154-
<!-- </app-box>-->
155-
156-
<!-- &lt;!&ndash; component with conditional content slots &ndash;&gt;-->
157-
<!-- <app-box [position]="[1, -1, 0]">-->
158-
<!-- @if (true) {-->
159-
<!-- <ngt-mesh-normal-material />-->
160-
<!-- }-->
161-
162-
<!-- @if (show()) {-->
163-
<!-- <app-box data-children [position]="[0.5, -0.5, 0]" color="black" />-->
164-
<!-- }-->
165-
<!-- </app-box>-->
166-
167-
<!-- &lt;!&ndash; component with conditional template &ndash;&gt;-->
168-
<!-- <app-condition-box [position]="[0, 2, 0]" />-->
169-
170-
<!-- &lt;!&ndash; component with conditional template under condition &ndash;&gt;-->
171-
<!-- @if (show()) {-->
172-
<!-- <app-condition-box [position]="[0, -2, 0]" />-->
173-
<!-- }-->
116+
<app-nested-box [position]="[-3, 0, 0]" />
117+
118+
<!-- three element under condition -->
119+
@if (show()) {
120+
<ngt-mesh [position]="[3, 0, 0]">
121+
<ngt-icosahedron-geometry />
122+
<ngt-mesh-normal-material />
123+
</ngt-mesh>
124+
}
125+
126+
<!-- component wrapping three elemnent -->
127+
<app-box [position]="[1, 0, 0]" />
128+
129+
<!-- with input for default content -->
130+
<app-box [position]="[-1, 0, 0]" color="red" />
131+
132+
<!-- with custom ng content -->
133+
<app-box [position]="[0, 1, 0]">
134+
<ngt-mesh-standard-material color="green" />
135+
</app-box>
136+
137+
<!-- with property binding for input for default content -->
138+
<app-box [position]="[0, -1, 0]" [color]="color()" />
139+
140+
<!-- component under condition -->
141+
@if (show()) {
142+
<app-box [position]="[1, 1, 0]">
143+
@if (show()) {
144+
<ngt-mesh-phong-material color="yellow" />
145+
}
146+
</app-box>
147+
}
148+
149+
<!-- component with component as content -->
150+
<app-box [position]="[-1, -1, 0]" color="brown" context="in root">
151+
<app-box data-children [position]="[-0.5, -0.5, 0]" color="pink" context="in box content in root" />
152+
</app-box>
153+
154+
<!-- component with both content projection slots -->
155+
<app-box [position]="[-1, 1, 0]">
156+
<ngt-mesh-lambert-material color="orange" />
157+
<app-box data-children [position]="[-0.5, 0.5, 0]" color="skyblue" />
158+
</app-box>
159+
160+
<!-- component with conditional content slots -->
161+
<app-box [position]="[1, -1, 0]">
162+
@if (true) {
163+
<ngt-mesh-normal-material />
164+
}
165+
166+
@if (show()) {
167+
<app-box data-children [position]="[0.5, -0.5, 0]" color="black" />
168+
}
169+
</app-box>
170+
171+
<!-- component with conditional template -->
172+
<app-condition-box [position]="[0, 2, 0]" />
173+
174+
<!-- component with conditional template under condition -->
175+
@if (show()) {
176+
<app-condition-box [position]="[0, -2, 0]" />
177+
}
174178
</ngt-group>
175179
176180
<!-- portal -->
177-
<!-- <ngt-portal [container]="virtualScene">-->
178-
<!-- <ngt-group *portalContent>-->
179-
<!-- &lt;!&ndash; component inside portal &ndash;&gt;-->
180-
<!-- <app-box context="in portal" />-->
181-
182-
<!-- @if (show()) {-->
183-
<!-- <app-box context="in portal in condition" />-->
184-
<!-- }-->
185-
<!-- </ngt-group>-->
186-
<!-- </ngt-portal>-->
181+
<ngt-portal [container]="virtualScene">
182+
<ngt-group *portalContent>
183+
<!-- component inside portal -->
184+
<app-box context="in portal" />
185+
186+
@if (show()) {
187+
<app-box context="in portal in condition" />
188+
}
189+
</ngt-group>
190+
</ngt-portal>
187191
`,
188192
imports: [NgtArgs, Box, ConditionBox, NgtPortalDeclarations, NestedBox],
189193
changeDetection: ChangeDetectionStrategy.OnPush,

apps/kitchen-sink-new/src/app/misc/misc.routes.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,17 @@ const routes: Routes = [
55
path: 'basic',
66
loadComponent: () => import('./basic/basic'),
77
},
8+
{
9+
path: 'svg-renderer',
10+
loadComponent: () => import('./svg-renderer/svg-renderer'),
11+
data: {
12+
credits: {
13+
title: 'SVG Renderer w/ Lines',
14+
link: 'https://threejs.org/examples/#svg_lines',
15+
class: 'text-white',
16+
},
17+
},
18+
},
819
{
920
path: '',
1021
redirectTo: 'basic',
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { ChangeDetectionStrategy, Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
2+
import { injectBeforeRender, NgtArgs } from 'angular-three';
3+
import { BufferGeometry, Float32BufferAttribute } from 'three';
4+
5+
@Component({
6+
selector: 'app-scene-graph',
7+
template: `
8+
<ngt-color attach="background" *args="['black']" />
9+
10+
@for (i of [1, 2, 3]; track $index) {
11+
<ngt-line [geometry]="geometry" [scale]="i / 3">
12+
<ngt-line-basic-material [color]="Math.random() * whiteHex" [linewidth]="10" />
13+
</ngt-line>
14+
}
15+
16+
<ngt-line [geometry]="geometry" [scale]="2">
17+
<ngt-line-dashed-material color="blue" [linewidth]="1" [dashSize]="10" [gapSize]="10" />
18+
</ngt-line>
19+
`,
20+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
21+
changeDetection: ChangeDetectionStrategy.OnPush,
22+
imports: [NgtArgs],
23+
})
24+
export class SceneGraph {
25+
protected readonly Math = Math;
26+
27+
protected whiteHex = 0xffffff;
28+
protected geometry = (() => {
29+
const divisions = 50;
30+
const vertices: number[] = [];
31+
32+
for (let i = 0; i <= divisions; i++) {
33+
const v = (i / divisions) * (Math.PI * 2);
34+
35+
const x = Math.sin(v);
36+
const z = Math.cos(v);
37+
38+
vertices.push(x, 0, z);
39+
}
40+
41+
const geometry = new BufferGeometry();
42+
geometry.setAttribute('position', new Float32BufferAttribute(vertices, 3));
43+
44+
return geometry;
45+
})();
46+
47+
constructor() {
48+
injectBeforeRender(({ scene }) => {
49+
let count = 0;
50+
const time = performance.now() / 1000;
51+
scene.traverse((child) => {
52+
child.rotation.x = count + time / 3;
53+
child.rotation.z = count + time / 4;
54+
count++;
55+
});
56+
});
57+
}
58+
}

0 commit comments

Comments
 (0)