Skip to content

Commit 6bc743c

Browse files
Chau TranChau Tran
Chau Tran
authored and
Chau Tran
committed
feat(soba): migrate catmull rom line
1 parent d4e5840 commit 6bc743c

File tree

4 files changed

+162
-72
lines changed

4 files changed

+162
-72
lines changed

libs/angular-three/src/lib/di/ref.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,7 @@ export function injectNgtRef<TElement>(
5858
Object.defineProperty(ref, 'nativeElement', {
5959
set: (newElement) => {
6060
if (newElement !== untracked(signalRef)) {
61-
try {
62-
signalRef.set(newElement);
63-
} catch {
64-
requestAnimationFrame(() => signalRef.set(newElement));
65-
}
61+
signalRef.set(newElement);
6662
safeDetectChanges(cdr);
6763
}
6864
},
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import { Component, computed, CUSTOM_ELEMENTS_SCHEMA, Input } from '@angular/core';
2+
import { injectNgtRef } from 'angular-three';
3+
import * as THREE from 'three';
4+
import { CatmullRomCurve3 } from 'three';
5+
import { Line2 } from 'three-stdlib';
6+
import { NgtsLine } from '../line/line';
7+
import { NgtsLineInputs } from '../line/line-input';
8+
9+
declare module '../line/line-input' {
10+
interface NgtsLineState {
11+
closed: boolean;
12+
curveType: 'centripetal' | 'chordal' | 'catmullrom';
13+
tension: number;
14+
}
15+
}
16+
17+
@Component({
18+
selector: 'ngts-catmull-rom-line',
19+
standalone: true,
20+
template: `
21+
<ngts-line
22+
[lineRef]="lineRef"
23+
[points]="segmentedPoints()"
24+
[vertexColors]="interpolatedVertexColors()"
25+
[color]="lineParameters().color"
26+
[resolution]="lineParameters().resolution"
27+
[lineWidth]="lineParameters().linewidth"
28+
[alphaToCoverage]="lineParameters().alphaToCoverage"
29+
[dashed]="lineParameters().dashed"
30+
[dashScale]="lineParameters().dashScale"
31+
[dashSize]="lineParameters().dashSize"
32+
[dashOffset]="lineParameters().dashOffset"
33+
[gapSize]="lineParameters().gapSize"
34+
[wireframe]="lineParameters().wireframe"
35+
[worldUnits]="lineParameters().worldUnits"
36+
/>
37+
`,
38+
imports: [NgtsLine],
39+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
40+
})
41+
export class NgtsCatmullRomLine extends NgtsLineInputs {
42+
@Input() lineRef = injectNgtRef<Line2>();
43+
44+
@Input({ required: true }) set points(
45+
points: Array<THREE.Vector3 | THREE.Vector2 | [number, number, number] | [number, number] | number>
46+
) {
47+
this.set({ points });
48+
}
49+
50+
@Input() set closed(closed: boolean) {
51+
this.set({ closed });
52+
}
53+
54+
@Input() set curveType(curveType: 'centripetal' | 'chordal' | 'catmullrom') {
55+
this.set({ curveType });
56+
}
57+
58+
@Input() set tension(tension: number) {
59+
this.set({ tension });
60+
}
61+
62+
@Input() set segments(segments: number) {
63+
this.set({ segments });
64+
}
65+
66+
readonly #curve = computed(() => {
67+
const points = this.select('points');
68+
const closed = this.select('closed');
69+
const curveType = this.select('curveType');
70+
const tension = this.select('tension');
71+
const mappedPoints = points().map((p) =>
72+
p instanceof THREE.Vector3 ? p : new THREE.Vector3(...(p as [number, number, number]))
73+
);
74+
return new CatmullRomCurve3(mappedPoints, closed(), curveType(), tension());
75+
});
76+
77+
readonly segmentedPoints = computed(() => {
78+
const curve = this.#curve();
79+
const segments = this.select('segments');
80+
return curve.getPoints(segments() as number);
81+
});
82+
83+
readonly interpolatedVertexColors = computed(() => {
84+
const vertexColors = this.select('vertexColors')();
85+
const segments = this.select('segments')() as number;
86+
87+
if (!vertexColors || vertexColors.length < 2) return undefined;
88+
if (vertexColors.length === segments + 1) return vertexColors;
89+
90+
const mappedColors = vertexColors.map((color: THREE.Color | [number, number, number]) =>
91+
color instanceof THREE.Color ? color : new THREE.Color(...color)
92+
);
93+
if (this.get('closed')) mappedColors.push(mappedColors[0].clone());
94+
95+
const iColors: THREE.Color[] = [mappedColors[0]];
96+
const divisions = segments / (mappedColors.length - 1);
97+
for (let i = 0; i < segments; i++) {
98+
const alpha = (i % divisions) / divisions;
99+
const colorIndex = Math.floor(i / divisions);
100+
iColors.push(mappedColors[colorIndex].clone().lerp(mappedColors[colorIndex + 1], alpha));
101+
}
102+
iColors.push(mappedColors[mappedColors.length - 1]);
103+
return iColors;
104+
});
105+
106+
constructor() {
107+
super();
108+
this.set({ closed: false, curveType: 'centripetal', tension: 0.5, segments: 64 });
109+
}
110+
}

libs/soba/abstractions/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export * from './billboard/billboard';
2+
export * from './catmull-rom-line/catmull-rom-line';
23
export * from './cubic-bezier-line/cubic-bezier-line';
34
export * from './line/line';
45
export * from './quadratic-bezier-line/quadratic-bezier-line';

libs/soba/src/abstractions/line.stories.ts

Lines changed: 50 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { Component, CUSTOM_ELEMENTS_SCHEMA, Input } from '@angular/core';
22
import { Meta, moduleMetadata, StoryObj } from '@storybook/angular';
3-
import { NgtsCubicBezierLine, NgtsLine, NgtsQuadraticBezierLine } from 'angular-three-soba/abstractions';
3+
import {
4+
NgtsCatmullRomLine,
5+
NgtsCubicBezierLine,
6+
NgtsLine,
7+
NgtsQuadraticBezierLine,
8+
} from 'angular-three-soba/abstractions';
49
import { NgtsOrbitControls } from 'angular-three-soba/controls';
510
import * as THREE from 'three';
611
import { GeometryUtils } from 'three-stdlib';
@@ -48,35 +53,35 @@ const defaultCatmullRom = {
4853
curveType: 'centripetal',
4954
};
5055

51-
// @Component({
52-
// standalone: true,
53-
// template: `
54-
// <ngts-catmull-rom-line
55-
// [points]="points"
56-
// [closed]="closed"
57-
// [curveType]="curveType"
58-
// [tension]="tension"
59-
// [segments]="segments"
60-
// [color]="color"
61-
// [lineWidth]="lineWidth"
62-
// [dashed]="dashed"
63-
// />
64-
// <ngts-orbit-controls [zoomSpeed]="0.5" />
65-
// `,
66-
// imports: [NgtsCatmullRomLine, NgtsOrbitControls],
67-
// schemas: [CUSTOM_ELEMENTS_SCHEMA],
68-
// })
69-
// class CatmullRomLineStory {
70-
// readonly points = defaultCatmullRom.points;
71-
// @Input() color = 'red';
72-
// @Input() lineWidth = 3;
73-
// @Input() dashed = false;
74-
// @Input() segments = defaultCatmullRom.segments;
75-
// @Input() closed = defaultCatmullRom.closed;
76-
// @Input() curveType = defaultCatmullRom.curveType;
77-
// @Input() tension = defaultCatmullRom.tension;
78-
// }
79-
//
56+
@Component({
57+
standalone: true,
58+
template: `
59+
<ngts-catmull-rom-line
60+
[points]="points"
61+
[closed]="closed"
62+
[curveType]="curveType"
63+
[tension]="tension"
64+
[segments]="segments"
65+
[color]="color"
66+
[lineWidth]="lineWidth"
67+
[dashed]="dashed"
68+
/>
69+
<ngts-orbit-controls [zoomSpeed]="0.5" />
70+
`,
71+
imports: [NgtsCatmullRomLine, NgtsOrbitControls],
72+
schemas: [CUSTOM_ELEMENTS_SCHEMA],
73+
})
74+
class CatmullRomLineStory {
75+
readonly points = defaultCatmullRom.points;
76+
@Input() color = 'red';
77+
@Input() lineWidth = 3;
78+
@Input() dashed = false;
79+
@Input() segments = defaultCatmullRom.segments;
80+
@Input() closed = defaultCatmullRom.closed;
81+
@Input() curveType = defaultCatmullRom.curveType;
82+
@Input() tension = defaultCatmullRom.tension;
83+
}
84+
8085
@Component({
8186
standalone: true,
8287
template: `
@@ -179,54 +184,32 @@ export default {
179184
decorators: [moduleMetadata({ imports: [StorybookSetup] })],
180185
} as Meta;
181186

187+
const canvasOptions = { camera: { position: [0, 0, 17] }, controls: false };
188+
182189
export const Default: StoryObj = {
183-
render: makeRenderFunction(DefaultLineStory, { camera: { position: [0, 0, 17] }, controls: false }),
190+
render: makeRenderFunction(DefaultLineStory, canvasOptions),
184191
args: { color: 'red', dashed: false, lineWidth: 3 },
185192
};
186193

187194
export const VertexColors: StoryObj = {
188-
render: makeRenderFunction(VertexColorsLineStory, { camera: { position: [0, 0, 17] }, controls: false }),
195+
render: makeRenderFunction(VertexColorsLineStory, canvasOptions),
189196
args: { color: 'red', dashed: false, lineWidth: 3 },
190197
};
191198

192199
export const CubicBezierLine: StoryObj = {
193-
render: makeRenderFunction(CubicBezierLineStory, { camera: { position: [0, 0, 17] }, controls: false }),
194-
args: {
195-
...defaultCubicBezier,
196-
color: 'red',
197-
lineWidth: 3,
198-
dashed: false,
199-
},
200+
render: makeRenderFunction(CubicBezierLineStory, canvasOptions),
201+
args: { ...defaultCubicBezier, color: 'red', lineWidth: 3, dashed: false },
200202
};
201203

202204
export const QuadraticBezierLine: StoryObj = {
203-
render: makeRenderFunction(QuadraticBezierLineStory, { camera: { position: [0, 0, 17] }, controls: false }),
204-
args: {
205-
...defaultQuadraticBezier,
206-
color: 'red',
207-
lineWidth: 3,
208-
dashed: false,
205+
render: makeRenderFunction(QuadraticBezierLineStory, canvasOptions),
206+
args: { ...defaultQuadraticBezier, color: 'red', lineWidth: 3, dashed: false },
207+
};
208+
209+
export const CatmullRomLine: StoryObj = {
210+
render: makeRenderFunction(CatmullRomLineStory, canvasOptions),
211+
args: { ...defaultCatmullRom, color: 'red', lineWidth: 3, dashed: false },
212+
argTypes: {
213+
curveType: { options: ['centripetal', 'chordal', 'catmullrom'], control: { type: 'select' } },
209214
},
210215
};
211-
//
212-
// export const CatmullRomLine: StoryObj = {
213-
// render: (args) => ({
214-
// props: {
215-
// story: CatmullRomLineStory,
216-
// options: makeCanvasOptions({ camera: { position: [0, 0, 17] }, controls: false }),
217-
// inputs: args,
218-
// },
219-
// template: `
220-
// <storybook-setup [story]="story" [options]="options" [inputs]="inputs" />
221-
// `,
222-
// }),
223-
// args: {
224-
// ...defaultCatmullRom,
225-
// color: 'red',
226-
// lineWidth: 3,
227-
// dashed: false,
228-
// },
229-
// argTypes: {
230-
// curveType: { options: ['centripetal', 'chordal', 'catmullrom'], control: { type: 'select' } },
231-
// },
232-
// };

0 commit comments

Comments
 (0)