Skip to content

Commit a5cf82b

Browse files
committed
fixed track layering
1 parent fcdfd8e commit a5cf82b

File tree

2 files changed

+195
-23
lines changed

2 files changed

+195
-23
lines changed

src/tracks/track/track.spec.ts

Lines changed: 190 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,18 +36,18 @@ describe('The Track Object', () => {
3636
});
3737

3838
it('should be able to add clips', async () => {
39-
await track.add(new Clip().set({ stop: 5, start: 0 }));
39+
await track.add(new Clip({ stop: 5, start: 0 }));
4040
expect(track.clips.length).toBe(1);
4141
expect(track.start.frames).toBe(0);
4242
expect(track.stop.frames).toBe(5);
4343

44-
await track.add(new Clip().set({ stop: 12, start: 9 }));
44+
await track.add(new Clip({ stop: 12, start: 9 }));
4545
expect(track.clips.length).toBe(2);
4646
expect(track.start.frames).toBe(0);
4747
expect(track.stop.frames).toBe(12);
4848
expect(track.clips.at(0)?.stop.frames).toBe(5);
4949

50-
await track.add(new Clip().set({ stop: 8, start: 6 }));
50+
await track.add(new Clip({ stop: 8, start: 6 }));
5151
expect(track.clips.length).toBe(3);
5252

5353
expect(track.start.frames).toBe(0);
@@ -58,8 +58,8 @@ describe('The Track Object', () => {
5858
});
5959

6060
it('should snap the clip when it overlaps with the end of another clip', async () => {
61-
const clip0 = new Clip().set({ stop: 20, start: 0 });
62-
const clip1 = new Clip().set({ stop: 30, start: 11 });
61+
const clip0 = new Clip({ stop: 20, start: 0 });
62+
const clip1 = new Clip({ stop: 30, start: 11 });
6363
await track.add(clip0);
6464
await track.add(clip1);
6565

@@ -78,8 +78,8 @@ describe('The Track Object', () => {
7878
});
7979

8080
it('should snap the clip when it overlaps with the start of another clip', async () => {
81-
const clip0 = new Clip().set({ stop: 30, start: 10 });
82-
const clip1 = new Clip().set({ stop: 19, start: 0 });
81+
const clip0 = new Clip({ stop: 30, start: 10 });
82+
const clip1 = new Clip({ stop: 19, start: 0 });
8383
await track.add(clip0);
8484
await track.add(clip1);
8585

@@ -98,9 +98,9 @@ describe('The Track Object', () => {
9898
});
9999

100100
it('should snap the clip when it overlaps with the start and end another clips', async () => {
101-
const clip0 = new Clip().set({ stop: 30, start: 17 });
102-
const clip1 = new Clip().set({ stop: 13, start: 0 });
103-
const clip2 = new Clip().set({ stop: 20, start: 10 });
101+
const clip0 = new Clip({ stop: 30, start: 17 });
102+
const clip1 = new Clip({ stop: 13, start: 0 });
103+
const clip2 = new Clip({ stop: 20, start: 10 });
104104

105105
await track.add(clip0);
106106
await track.add(clip1);
@@ -128,8 +128,8 @@ describe('The Track Object', () => {
128128

129129
it('should stack clips if the option is active', async () => {
130130
track.stacked();
131-
await track.add(new Clip().set({ stop: 9, start: 0 }));
132-
await track.add(new Clip().set({ stop: 45, start: 30 }));
131+
await track.add(new Clip({ stop: 9, start: 0 }));
132+
await track.add(new Clip({ stop: 45, start: 30 }));
133133

134134
expect(track.clips.at(0)?.start.frames).toBe(0);
135135
expect(track.clips.at(0)?.stop.frames).toBe(9);
@@ -140,20 +140,20 @@ describe('The Track Object', () => {
140140
expect(track.clips.at(1)?.stop.frames).toBe(24);
141141
expect(track.clips.at(1)?.stop.millis).toBe(801);
142142

143-
await track.add(new Clip().set({ stop: 50, start: 40 }));
143+
await track.add(new Clip({ stop: 50, start: 40 }));
144144
expect(track.clips.at(2)?.start.millis).toBe(802);
145145
expect(track.clips.at(2)?.start.frames).toBe(24);
146146
expect(track.clips.at(2)?.stop.frames).toBe(34);
147147
});
148148

149149
it('should render the clips correctly', async () => {
150-
const clip0 = new Clip().set({ stop: 9, start: 3 });
150+
const clip0 = new Clip({ stop: 9, start: 3 });
151151
const updateSpy0 = vi.spyOn(clip0, 'update');
152152

153-
const clip1 = new Clip().set({ stop: 14, start: 10 });
153+
const clip1 = new Clip({ stop: 14, start: 10 });
154154
const updateSpy1 = vi.spyOn(clip1, 'update');
155155

156-
const clip2 = new Clip().set({ stop: 26, start: 20 });
156+
const clip2 = new Clip({ stop: 26, start: 20 });
157157
const updateSpy2 = vi.spyOn(clip2, 'update');
158158

159159
await track.add(clip0);
@@ -221,7 +221,7 @@ describe('The Track Object', () => {
221221

222222
await track.add(clip0);
223223
await track.add(clip1);
224-
224+
225225
expect(track.clips.length).toBe(2);
226226

227227
composition.computeFrame();
@@ -254,12 +254,12 @@ describe('The Track Object', () => {
254254
it('should realign the clips when stacked', async () => {
255255
track.stacked();
256256

257-
const clip0 = new Clip().set({ stop: 9, start: 0 });
258-
const clip1 = new Clip().set({ stop: 45, start: 30 });
257+
const clip0 = new Clip({ stop: 9, start: 0 });
258+
const clip1 = new Clip({ stop: 45, start: 30 });
259259

260260
await track.add(clip0);
261261
await track.add(clip1);
262-
await track.add(new Clip().set({ stop: 50, start: 40 }));
262+
await track.add(new Clip({ stop: 50, start: 40 }));
263263

264264
expect(track.clips.at(0)?.start.frames).toBe(0);
265265
expect(track.clips.at(0)?.stop.frames).toBe(9);
@@ -291,7 +291,7 @@ describe('The Track Object', () => {
291291
});
292292

293293
it('should be be able to add a base clip with offset', async () => {
294-
const clip = new Clip().set({ stop: 30 });
294+
const clip = new Clip({ stop: 30 });
295295

296296
await track.add(clip.offsetBy(60));
297297

@@ -300,7 +300,7 @@ describe('The Track Object', () => {
300300
});
301301

302302
it('should be be able to add a base clip with offset', async () => {
303-
const clip = new Clip().set({ stop: 30 });
303+
const clip = new Clip({ stop: 30 });
304304

305305
await track.add(clip.offsetBy(60));
306306

@@ -407,3 +407,171 @@ describe('The Track Object', () => {
407407
expect(exitFn).toHaveBeenCalledTimes(1);
408408
});
409409
});
410+
411+
describe("The Track Object's layers method", () => {
412+
let composition: Composition;
413+
let track0: Track<Clip>;
414+
let track1: Track<Clip>;
415+
let track2: Track<Clip>;
416+
let track3: Track<Clip>;
417+
418+
beforeEach(() => {
419+
composition = new Composition();
420+
track0 = composition.createTrack('base');
421+
track1 = composition.createTrack('base');
422+
track2 = composition.createTrack('base');
423+
track3 = composition.createTrack('base');
424+
425+
expect(composition.tracks.length).toBe(4);
426+
427+
// [tack3, track2, track1, track0]
428+
// [view0, view1, view2, view3]
429+
430+
expect(composition.tracks[0].id).toBe(track3.id);
431+
expect(composition.tracks[1].id).toBe(track2.id);
432+
expect(composition.tracks[2].id).toBe(track1.id);
433+
expect(composition.tracks[3].id).toBe(track0.id);
434+
435+
expect(composition.stage.children[0].uid).toBe(track0.view.uid);
436+
expect(composition.stage.children[1].uid).toBe(track1.view.uid);
437+
expect(composition.stage.children[2].uid).toBe(track2.view.uid);
438+
expect(composition.stage.children[3].uid).toBe(track3.view.uid);
439+
});
440+
441+
it("should have a 'top' argument", () => {
442+
track2.layer('top');
443+
444+
// [track2, tack3, track1, track0]
445+
// [view0, view1, view3, view2]
446+
447+
expect(composition.tracks[0].id).toBe(track2.id);
448+
expect(composition.tracks[1].id).toBe(track3.id);
449+
expect(composition.tracks[2].id).toBe(track1.id);
450+
expect(composition.tracks[3].id).toBe(track0.id);
451+
452+
expect(composition.stage.children[0].uid).toBe(track0.view.uid);
453+
expect(composition.stage.children[1].uid).toBe(track1.view.uid);
454+
expect(composition.stage.children[2].uid).toBe(track3.view.uid);
455+
expect(composition.stage.children[3].uid).toBe(track2.view.uid);
456+
});
457+
458+
it("should have a 'bottom' argument", () => {
459+
track2.layer('bottom');
460+
461+
// [tack3, track1, track0, track2]
462+
// [view2, view0, view1, view3]
463+
464+
expect(composition.tracks[0].id).toBe(track3.id);
465+
expect(composition.tracks[1].id).toBe(track1.id);
466+
expect(composition.tracks[2].id).toBe(track0.id);
467+
expect(composition.tracks[3].id).toBe(track2.id);
468+
469+
expect(composition.stage.children[0].uid).toBe(track2.view.uid);
470+
expect(composition.stage.children[1].uid).toBe(track0.view.uid);
471+
expect(composition.stage.children[2].uid).toBe(track1.view.uid);
472+
expect(composition.stage.children[3].uid).toBe(track3.view.uid);
473+
});
474+
475+
it("should accept a valid index", () => {
476+
track3.layer(2);
477+
478+
// [track2, track1, tack3, track0]
479+
// [view0, view3, view1, view2]
480+
481+
expect(composition.tracks[0].id).toBe(track2.id);
482+
expect(composition.tracks[1].id).toBe(track1.id);
483+
expect(composition.tracks[2].id).toBe(track3.id);
484+
expect(composition.tracks[3].id).toBe(track0.id);
485+
486+
expect(composition.stage.children[0].uid).toBe(track0.view.uid);
487+
expect(composition.stage.children[1].uid).toBe(track3.view.uid);
488+
expect(composition.stage.children[2].uid).toBe(track1.view.uid);
489+
expect(composition.stage.children[3].uid).toBe(track2.view.uid);
490+
});
491+
492+
it("should accept invalid indexes", () => {
493+
track2.layer(-5);
494+
495+
// [track2, tack3, track1, track0]
496+
// [view0, view1, view3, view2]
497+
498+
expect(composition.tracks[0].id).toBe(track2.id);
499+
expect(composition.tracks[1].id).toBe(track3.id);
500+
expect(composition.tracks[2].id).toBe(track1.id);
501+
expect(composition.tracks[3].id).toBe(track0.id);
502+
503+
expect(composition.stage.children[0].uid).toBe(track0.view.uid);
504+
expect(composition.stage.children[1].uid).toBe(track1.view.uid);
505+
expect(composition.stage.children[2].uid).toBe(track3.view.uid);
506+
expect(composition.stage.children[3].uid).toBe(track2.view.uid);
507+
508+
509+
track3.layer(6);
510+
511+
// [track2, track1, track0, tack3]
512+
// [view3, view0, view1, view2]
513+
514+
expect(composition.tracks[0].id).toBe(track2.id);
515+
expect(composition.tracks[1].id).toBe(track1.id);
516+
expect(composition.tracks[2].id).toBe(track0.id);
517+
expect(composition.tracks[3].id).toBe(track3.id);
518+
519+
expect(composition.stage.children[0].uid).toBe(track3.view.uid);
520+
expect(composition.stage.children[1].uid).toBe(track0.view.uid);
521+
expect(composition.stage.children[2].uid).toBe(track1.view.uid);
522+
expect(composition.stage.children[3].uid).toBe(track2.view.uid);
523+
});
524+
525+
it("should work properly with 1 and 2 tracks", () => {
526+
composition.removeTrack(track3);
527+
composition.removeTrack(track2);
528+
expect(composition.tracks.length).toBe(2);
529+
530+
// [track1, track0]
531+
// [view0, view1]
532+
533+
expect(composition.tracks[0].id).toBe(track1.id);
534+
expect(composition.tracks[1].id).toBe(track0.id);
535+
536+
expect(composition.stage.children[0].uid).toBe(track0.view.uid);
537+
expect(composition.stage.children[1].uid).toBe(track1.view.uid);
538+
539+
track0.layer('top');
540+
541+
// [track0, track1]
542+
// [view1, view0]
543+
544+
expect(composition.tracks[0].id).toBe(track0.id);
545+
expect(composition.tracks[1].id).toBe(track1.id);
546+
547+
expect(composition.stage.children[0].uid).toBe(track1.view.uid);
548+
expect(composition.stage.children[1].uid).toBe(track0.view.uid);
549+
550+
track1.layer(0);
551+
552+
// [track1, track0]
553+
// [view0, view1]
554+
555+
expect(composition.tracks[0].id).toBe(track1.id);
556+
expect(composition.tracks[1].id).toBe(track0.id);
557+
558+
expect(composition.stage.children[0].uid).toBe(track0.view.uid);
559+
expect(composition.stage.children[1].uid).toBe(track1.view.uid);
560+
561+
composition.removeTrack(track0);
562+
563+
expect(composition.tracks.length).toBe(1);
564+
expect(composition.stage.children.length).toBe(1);
565+
566+
// [track1]
567+
// [view1]
568+
569+
expect(composition.tracks[0].id).toBe(track1.id);
570+
expect(composition.stage.children[0].uid).toBe(track1.view.uid);
571+
572+
track1.layer('top');
573+
574+
expect(composition.tracks[0].id).toBe(track1.id);
575+
expect(composition.stage.children[0].uid).toBe(track1.view.uid);
576+
});
577+
});

src/tracks/track/track.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,14 +80,18 @@ export class Track<Clp extends Clip> extends EventEmitterMixin(Serializer) {
8080
public layer(layer: TrackLayer): this {
8181
const tracks = this.composition?.tracks ?? [];
8282
const fromIndex = tracks.findIndex((n) => n.id == this.id);
83+
const lastIndex = tracks.length - 1;
8384
if (fromIndex == -1) return this;
8485

8586
let toIndex = 0;
86-
if (layer == 'bottom') toIndex = tracks.length;
87+
if (layer == 'bottom') toIndex = lastIndex;
8788
else if (layer == 'top') toIndex = 0;
89+
else if (layer < 0) toIndex = 0;
90+
else if (layer > lastIndex) toIndex = lastIndex;
8891
else toIndex = layer;
8992

9093
arraymove(tracks, fromIndex, toIndex);
94+
this.composition?.stage.setChildIndex(this.view, lastIndex - toIndex);
9195

9296
this.trigger('update', undefined);
9397
return this;

0 commit comments

Comments
 (0)