@flighthq/scene2d 0.2.1-next.840.857425c
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bitmap.d.ts +8 -0
- package/dist/bitmap.d.ts.map +1 -0
- package/dist/bitmap.js +41 -0
- package/dist/bitmap.js.map +1 -0
- package/dist/displayContainer.d.ts +5 -0
- package/dist/displayContainer.d.ts.map +1 -0
- package/dist/displayContainer.js +12 -0
- package/dist/displayContainer.js.map +1 -0
- package/dist/displayObject.d.ts +12 -0
- package/dist/displayObject.d.ts.map +1 -0
- package/dist/displayObject.js +87 -0
- package/dist/displayObject.js.map +1 -0
- package/dist/displayObjectAnimation.d.ts +3 -0
- package/dist/displayObjectAnimation.d.ts.map +1 -0
- package/dist/displayObjectAnimation.js +82 -0
- package/dist/displayObjectAnimation.js.map +1 -0
- package/dist/htmlView.d.ts +8 -0
- package/dist/htmlView.d.ts.map +1 -0
- package/dist/htmlView.js +35 -0
- package/dist/htmlView.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/renderView.d.ts +8 -0
- package/dist/renderView.d.ts.map +1 -0
- package/dist/renderView.js +35 -0
- package/dist/renderView.js.map +1 -0
- package/dist/scene2d.d.ts +10 -0
- package/dist/scene2d.d.ts.map +1 -0
- package/dist/scene2d.js +73 -0
- package/dist/scene2d.js.map +1 -0
- package/dist/video.d.ts +9 -0
- package/dist/video.d.ts.map +1 -0
- package/dist/video.js +41 -0
- package/dist/video.js.map +1 -0
- package/package.json +49 -0
- package/src/bitmap.test.ts +131 -0
- package/src/displayContainer.test.ts +37 -0
- package/src/displayObject.test.ts +241 -0
- package/src/displayObjectAnimation.test.ts +69 -0
- package/src/htmlView.test.ts +111 -0
- package/src/renderView.test.ts +104 -0
- package/src/scene2d.test.ts +165 -0
- package/src/video.test.ts +113 -0
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { createRectangle } from '@flighthq/geometry';
|
|
2
|
+
import type { Node, RenderView, RenderViewRenderer } from '@flighthq/types';
|
|
3
|
+
import { RenderViewKind } from '@flighthq/types';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
computeRenderViewLocalBoundsRectangle,
|
|
7
|
+
createRenderView,
|
|
8
|
+
createRenderViewData,
|
|
9
|
+
createRenderViewRuntime,
|
|
10
|
+
getRenderViewRuntime,
|
|
11
|
+
setRenderViewSize,
|
|
12
|
+
} from './renderView';
|
|
13
|
+
|
|
14
|
+
function makeRenderer(): RenderViewRenderer {
|
|
15
|
+
const canvas = document.createElement('canvas');
|
|
16
|
+
canvas.width = 100;
|
|
17
|
+
canvas.height = 100;
|
|
18
|
+
return { canvas, render: () => {} };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe('computeRenderViewLocalBoundsRectangle', () => {
|
|
22
|
+
it('writes width and height from data', () => {
|
|
23
|
+
const view = createRenderView({ data: { width: 400, height: 300 } });
|
|
24
|
+
const out = createRectangle(0, 0, 0, 0);
|
|
25
|
+
computeRenderViewLocalBoundsRectangle(out, view as unknown as Node);
|
|
26
|
+
expect(out.width).toBe(400);
|
|
27
|
+
expect(out.height).toBe(300);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('createRenderView', () => {
|
|
32
|
+
let view: RenderView;
|
|
33
|
+
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
view = createRenderView();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('initializes default values', () => {
|
|
39
|
+
expect(view.data.renderer).toBeNull();
|
|
40
|
+
expect(view.data.width).toBe(0);
|
|
41
|
+
expect(view.data.height).toBe(0);
|
|
42
|
+
expect(view.kind).toStrictEqual(RenderViewKind);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('allows pre-defined values', () => {
|
|
46
|
+
const renderer = makeRenderer();
|
|
47
|
+
const obj = createRenderView({ data: { renderer, width: 320, height: 240 } });
|
|
48
|
+
expect(obj.data.renderer).toStrictEqual(renderer);
|
|
49
|
+
expect(obj.data.width).toBe(320);
|
|
50
|
+
expect(obj.data.height).toBe(240);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('returns a new object for better hidden-class performance', () => {
|
|
54
|
+
const base = {};
|
|
55
|
+
const obj = createRenderView(base);
|
|
56
|
+
expect(obj).not.toStrictEqual(base);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
describe('createRenderViewData', () => {
|
|
61
|
+
it('returns default values', () => {
|
|
62
|
+
const data = createRenderViewData();
|
|
63
|
+
expect(data.renderer).toBeNull();
|
|
64
|
+
expect(data.width).toBe(0);
|
|
65
|
+
expect(data.height).toBe(0);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('allows pre-defined values', () => {
|
|
69
|
+
const renderer = makeRenderer();
|
|
70
|
+
const data = createRenderViewData({ renderer, width: 800, height: 600 });
|
|
71
|
+
expect(data.renderer).toStrictEqual(renderer);
|
|
72
|
+
expect(data.width).toBe(800);
|
|
73
|
+
expect(data.height).toBe(600);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe('createRenderViewRuntime', () => {
|
|
78
|
+
it('returns a non-null runtime', () => {
|
|
79
|
+
expect(createRenderViewRuntime()).not.toBeNull();
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe('getRenderViewRuntime', () => {
|
|
84
|
+
it('returns the runtime for a RenderView', () => {
|
|
85
|
+
const view = createRenderView();
|
|
86
|
+
expect(getRenderViewRuntime(view)).not.toBeNull();
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe('setRenderViewSize', () => {
|
|
91
|
+
it('updates width and height', () => {
|
|
92
|
+
const view = createRenderView();
|
|
93
|
+
setRenderViewSize(view, 640, 480);
|
|
94
|
+
expect(view.data.width).toBe(640);
|
|
95
|
+
expect(view.data.height).toBe(480);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('is a no-op when size is unchanged', () => {
|
|
99
|
+
const view = createRenderView({ data: { width: 100, height: 100 } });
|
|
100
|
+
const before = view.data.width;
|
|
101
|
+
setRenderViewSize(view, 100, 100);
|
|
102
|
+
expect(view.data.width).toBe(before);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { addNodeChild } from '@flighthq/node';
|
|
2
|
+
import { connectSignal } from '@flighthq/signals';
|
|
3
|
+
import type { Scene2D } from '@flighthq/types';
|
|
4
|
+
|
|
5
|
+
import { createDisplayObject } from './displayObject';
|
|
6
|
+
import {
|
|
7
|
+
createScene2D,
|
|
8
|
+
createScene2DRuntime,
|
|
9
|
+
createScene2DSignals,
|
|
10
|
+
enableScene2DSignals,
|
|
11
|
+
getScene2DRoot,
|
|
12
|
+
getScene2DRuntime,
|
|
13
|
+
getScene2DSignals,
|
|
14
|
+
setScene2DSize,
|
|
15
|
+
} from './scene2d';
|
|
16
|
+
|
|
17
|
+
describe('createScene2D', () => {
|
|
18
|
+
let scene2d: Scene2D;
|
|
19
|
+
|
|
20
|
+
beforeEach(() => {
|
|
21
|
+
scene2d = createScene2D();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('initializes default values', () => {
|
|
25
|
+
expect(scene2d.color).toBe(null);
|
|
26
|
+
expect(scene2d.scene2dHeight).toBe(550);
|
|
27
|
+
expect(scene2d.scene2dWidth).toBe(400);
|
|
28
|
+
expect(scene2d.align).toBe('topleft');
|
|
29
|
+
expect(scene2d.scaleMode).toBe('noscale');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('allocates a display-object root the scene2d points back to', () => {
|
|
33
|
+
expect(scene2d.root).toBeDefined();
|
|
34
|
+
expect(getScene2DRoot(scene2d.root)).toBe(scene2d);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('allows pre-defined values', () => {
|
|
38
|
+
const obj = createScene2D({ color: 0xff0000ff, scene2dHeight: 1000, scene2dWidth: 2000 });
|
|
39
|
+
expect(obj.color).toStrictEqual(0xff0000ff);
|
|
40
|
+
expect(obj.scene2dHeight).toStrictEqual(1000);
|
|
41
|
+
expect(obj.scene2dWidth).toStrictEqual(2000);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
describe('createScene2DRuntime', () => {
|
|
46
|
+
it('returns a non-null runtime with scene2dSignals initialized to null', () => {
|
|
47
|
+
const runtime = createScene2DRuntime();
|
|
48
|
+
expect(runtime).not.toBeNull();
|
|
49
|
+
expect(runtime.scene2dSignals).toBeNull();
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe('createScene2DSignals', () => {
|
|
54
|
+
it('returns an object with all signal properties', () => {
|
|
55
|
+
const signals = createScene2DSignals();
|
|
56
|
+
expect(signals.onResize).toBeDefined();
|
|
57
|
+
expect(signals.onFullscreenChanged).toBeDefined();
|
|
58
|
+
expect(signals.onOrientationChanged).toBeDefined();
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe('enableScene2DSignals', () => {
|
|
63
|
+
it('creates and returns signals on first call', () => {
|
|
64
|
+
const scene2d = createScene2D();
|
|
65
|
+
const signals = enableScene2DSignals(scene2d);
|
|
66
|
+
expect(signals).toBeDefined();
|
|
67
|
+
expect(signals.onResize).toBeDefined();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('returns the same object on subsequent calls', () => {
|
|
71
|
+
const scene2d = createScene2D();
|
|
72
|
+
expect(enableScene2DSignals(scene2d)).toBe(enableScene2DSignals(scene2d));
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('makes getScene2DSignals return the enabled object', () => {
|
|
76
|
+
const scene2d = createScene2D();
|
|
77
|
+
const signals = enableScene2DSignals(scene2d);
|
|
78
|
+
expect(getScene2DSignals(scene2d)).toBe(signals);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe('getScene2DRoot', () => {
|
|
83
|
+
it('returns null when the node has no parent', () => {
|
|
84
|
+
const obj = createDisplayObject();
|
|
85
|
+
expect(getScene2DRoot(obj)).toBeNull();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('returns null when the root is not owned by a Scene2D', () => {
|
|
89
|
+
const root = createDisplayObject();
|
|
90
|
+
const child = createDisplayObject();
|
|
91
|
+
addNodeChild(root, child);
|
|
92
|
+
expect(getScene2DRoot(child)).toBeNull();
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('returns the Scene2D when a child is added under its root', () => {
|
|
96
|
+
const scene2d = createScene2D();
|
|
97
|
+
const child = createDisplayObject();
|
|
98
|
+
addNodeChild(scene2d.root, child);
|
|
99
|
+
expect(getScene2DRoot(child)).toBe(scene2d);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('returns the Scene2D from a deeply nested node', () => {
|
|
103
|
+
const scene2d = createScene2D();
|
|
104
|
+
const mid = createDisplayObject();
|
|
105
|
+
const leaf = createDisplayObject();
|
|
106
|
+
addNodeChild(scene2d.root, mid);
|
|
107
|
+
addNodeChild(mid, leaf);
|
|
108
|
+
expect(getScene2DRoot(leaf)).toBe(scene2d);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe('getScene2DRuntime', () => {
|
|
113
|
+
it('returns the runtime for a Scene2D', () => {
|
|
114
|
+
const scene2d = createScene2D();
|
|
115
|
+
const runtime = getScene2DRuntime(scene2d);
|
|
116
|
+
expect(runtime).not.toBeNull();
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
describe('getScene2DSignals', () => {
|
|
121
|
+
it('returns null before signals are enabled', () => {
|
|
122
|
+
const scene2d = createScene2D();
|
|
123
|
+
expect(getScene2DSignals(scene2d)).toBeNull();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('returns the signals after enableScene2DSignals', () => {
|
|
127
|
+
const scene2d = createScene2D();
|
|
128
|
+
const signals = enableScene2DSignals(scene2d);
|
|
129
|
+
expect(getScene2DSignals(scene2d)).toBe(signals);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
describe('setScene2DSize', () => {
|
|
134
|
+
it('updates scene2dWidth and scene2dHeight', () => {
|
|
135
|
+
const scene2d = createScene2D();
|
|
136
|
+
setScene2DSize(scene2d, 1920, 1080);
|
|
137
|
+
expect(scene2d.scene2dWidth).toBe(1920);
|
|
138
|
+
expect(scene2d.scene2dHeight).toBe(1080);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('emits onResize when dimensions change', () => {
|
|
142
|
+
const scene2d = createScene2D();
|
|
143
|
+
let called = false;
|
|
144
|
+
connectSignal(enableScene2DSignals(scene2d).onResize, () => {
|
|
145
|
+
called = true;
|
|
146
|
+
});
|
|
147
|
+
setScene2DSize(scene2d, 1280, 720);
|
|
148
|
+
expect(called).toBe(true);
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('does not emit onResize when dimensions are unchanged', () => {
|
|
152
|
+
const scene2d = createScene2D({ scene2dWidth: 400, scene2dHeight: 300 });
|
|
153
|
+
let called = false;
|
|
154
|
+
connectSignal(enableScene2DSignals(scene2d).onResize, () => {
|
|
155
|
+
called = true;
|
|
156
|
+
});
|
|
157
|
+
setScene2DSize(scene2d, 400, 300);
|
|
158
|
+
expect(called).toBe(false);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('does not emit onResize when no one has subscribed', () => {
|
|
162
|
+
const scene2d = createScene2D();
|
|
163
|
+
expect(() => setScene2DSize(scene2d, 1280, 720)).not.toThrow();
|
|
164
|
+
});
|
|
165
|
+
});
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { getNodeLocalBoundsRevision, getNodeLocalContentRevision, getNodeLocalTransformRevision } from '@flighthq/node';
|
|
2
|
+
import type { Video } from '@flighthq/types';
|
|
3
|
+
import { VideoKind } from '@flighthq/types';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
computeVideoLocalBoundsRectangle,
|
|
7
|
+
createVideo,
|
|
8
|
+
createVideoData,
|
|
9
|
+
createVideoRuntime,
|
|
10
|
+
getVideoRuntime,
|
|
11
|
+
setVideoSmoothing,
|
|
12
|
+
setVideoSource,
|
|
13
|
+
} from './video';
|
|
14
|
+
|
|
15
|
+
describe('computeVideoLocalBoundsRectangle', () => {
|
|
16
|
+
it('does not modify out when source element is null', () => {
|
|
17
|
+
const video = createVideo();
|
|
18
|
+
const out = { x: 0, y: 0, width: 0, height: 0 };
|
|
19
|
+
computeVideoLocalBoundsRectangle(out as never, video as never);
|
|
20
|
+
expect(out.width).toBe(0);
|
|
21
|
+
expect(out.height).toBe(0);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('sets out dimensions from the video element', () => {
|
|
25
|
+
const video = createVideo();
|
|
26
|
+
const el = document.createElement('video');
|
|
27
|
+
Object.defineProperty(el, 'videoWidth', { get: () => 320 });
|
|
28
|
+
Object.defineProperty(el, 'videoHeight', { get: () => 240 });
|
|
29
|
+
video.data.source = { element: el } as never;
|
|
30
|
+
const out = { x: 0, y: 0, width: 0, height: 0 };
|
|
31
|
+
computeVideoLocalBoundsRectangle(out as never, video as never);
|
|
32
|
+
expect(out.width).toBe(320);
|
|
33
|
+
expect(out.height).toBe(240);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe('createVideo', () => {
|
|
38
|
+
let video: Video;
|
|
39
|
+
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
video = createVideo();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('initializes default values', () => {
|
|
45
|
+
expect(video.data.smoothing).toBe(true);
|
|
46
|
+
expect(video.kind).toStrictEqual(VideoKind);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('allows pre-defined values', () => {
|
|
50
|
+
const base = {
|
|
51
|
+
data: {
|
|
52
|
+
smoothing: false,
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
const obj = createVideo(base);
|
|
56
|
+
expect(obj.data.smoothing).toStrictEqual(base.data.smoothing);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('returns a new object for better hidden-class performance', () => {
|
|
60
|
+
const base = {};
|
|
61
|
+
const obj = createVideo(base);
|
|
62
|
+
expect(obj).not.toStrictEqual(base);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
describe('createVideoData', () => {
|
|
67
|
+
it('returns default values', () => {
|
|
68
|
+
const data = createVideoData();
|
|
69
|
+
expect(data.smoothing).toBe(true);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('allows pre-defined values', () => {
|
|
73
|
+
const data = createVideoData({ smoothing: false });
|
|
74
|
+
expect(data.smoothing).toBe(false);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe('createVideoRuntime', () => {
|
|
79
|
+
it('returns a non-null runtime', () => {
|
|
80
|
+
const runtime = createVideoRuntime();
|
|
81
|
+
expect(runtime).not.toBeNull();
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe('getVideoRuntime', () => {
|
|
86
|
+
it('returns the runtime for a Video', () => {
|
|
87
|
+
const video = createVideo();
|
|
88
|
+
const runtime = getVideoRuntime(video);
|
|
89
|
+
expect(runtime).not.toBeNull();
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe('setVideoSmoothing', () => {
|
|
94
|
+
it('updates the smoothing field', () => {
|
|
95
|
+
const video = createVideo();
|
|
96
|
+
setVideoSmoothing(video, false);
|
|
97
|
+
expect(video.data.smoothing).toBe(false);
|
|
98
|
+
setVideoSmoothing(video, true);
|
|
99
|
+
expect(video.data.smoothing).toBe(true);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('setVideoSource', () => {
|
|
104
|
+
it('updates the source field', () => {
|
|
105
|
+
const video = createVideo();
|
|
106
|
+
const el = document.createElement('video');
|
|
107
|
+
const source = { element: el } as never;
|
|
108
|
+
setVideoSource(video, source);
|
|
109
|
+
expect(video.data.source).toBe(source);
|
|
110
|
+
setVideoSource(video, null);
|
|
111
|
+
expect(video.data.source).toBeNull();
|
|
112
|
+
});
|
|
113
|
+
});
|