소스 검색

Merge branch 'ts-defs'

customisations
alemart 2 달 전
부모
커밋
762683e3b4

+ 1
- 0
.gitignore 파일 보기

@@ -26,3 +26,4 @@ www/
26 26
 site/
27 27
 docs/__pycache__/*
28 28
 demos/**/*.blend1
29
+build/

+ 1
- 1
demos/hello-three/demo.js 파일 보기

@@ -69,7 +69,7 @@ class Utils
69 69
             return null;
70 70
 
71 71
         for(const result of ar.frame.results) {
72
-            if(result.tracker.type == 'image-tracker') {
72
+            if(result.of('image-tracker')) {
73 73
                 if(result.trackables.length > 0) {
74 74
                     const trackable = result.trackables[0];
75 75
                     return trackable.referenceImage.name;

+ 1
- 1
demos/hello-world/demo.js 파일 보기

@@ -93,7 +93,7 @@ function animate(time, frame)
93 93
 function mix(frame)
94 94
 {
95 95
     for(const result of frame.results) {
96
-        if(result.tracker.type == 'image-tracker') {
96
+        if(result.of('image-tracker')) {
97 97
             if(result.trackables.length > 0) {
98 98
                 const trackable = result.trackables[0];
99 99
                 const projectionMatrix = result.viewer.view.projectionMatrix;

+ 1
- 1
demos/pointer-demo/demo.js 파일 보기

@@ -142,7 +142,7 @@ function animate(time, frame)
142 142
 function read(frame)
143 143
 {
144 144
     for(const result of frame.results) {
145
-        if(result.tracker.type == 'pointer-tracker') {
145
+        if(result.of('pointer-tracker')) {
146 146
             const pointers = result.trackables;
147 147
             return pointers;
148 148
         }

+ 35
- 1
docs/api/tracker-result.md 파일 보기

@@ -14,4 +14,38 @@ A reference to the [tracker](tracker.md) that generated this result.
14 14
 
15 15
 `result.trackables: Trackable[], read-only`
16 16
 
17
-An array of zero or more [trackables](trackable.md).
17
+An array of zero or more [trackables](trackable.md).
18
+
19
+## Methods
20
+
21
+### of
22
+
23
+`result.of(trackerType: string): boolean`
24
+
25
+Checks if `this` result was generated by tracker of a certain `trackerType`. This is a convenient type guard for TypeScript users. See also: [Tracker.is](./tracker.md#is).
26
+
27
+*Since:* 0.4.4
28
+
29
+**Returns**
30
+
31
+The same as `tracker.is(trackerType)`.
32
+
33
+**Example**
34
+
35
+```ts
36
+let result: TrackerResult;
37
+
38
+// ...
39
+
40
+if(result.of('image-tracker')) {
41
+    // result is inferred to be an ImageTrackerResult
42
+    // ...
43
+}
44
+else if(result.of('pointer-tracker')) {
45
+    // result is inferred to be a PointerTrackerResult
46
+    // ...
47
+}
48
+else {
49
+    // ...
50
+}
51
+```

+ 38
- 2
docs/api/tracker.md 파일 보기

@@ -2,7 +2,7 @@
2 2
 
3 3
 An interface that represents a generic tracker. Trackers analyze input data in some way and are meant to be attached to a [session](session.md). Refer to the [concepts](../tutorial/concepts.md) for more information.
4 4
 
5
-An [Image Tracker](image-tracker.md) is an implementation of a tracker.
5
+An [Image Tracker](image-tracker.md) is an implementation of a tracker, and so is a [PointerTracker](pointer-tracker.md).
6 6
 
7 7
 ## Properties
8 8
 
@@ -10,4 +10,40 @@ An [Image Tracker](image-tracker.md) is an implementation of a tracker.
10 10
 
11 11
 `tracker.type: string, read-only`
12 12
 
13
-A string representing the type of the tracker.
13
+A string representing the type of the tracker.
14
+
15
+*Deprecated since:* 0.4.4. Use `tracker.is()` instead.
16
+
17
+## Methods
18
+
19
+### is
20
+
21
+`tracker.is(type: string): boolean`
22
+
23
+Checks if `this` tracker is of a certain `type`. This is a convenient type guard for TypeScript users. See also: [TrackerResult.of](./tracker-result.md#of).
24
+
25
+*Since:* 0.4.4
26
+
27
+**Returns**
28
+
29
+`true` if and only if `type === tracker.type`
30
+
31
+**Example**
32
+
33
+```ts
34
+let tracker: Tracker;
35
+
36
+// ...
37
+
38
+if(tracker.is('image-tracker')) {
39
+    // tracker is inferred to be an ImageTracker
40
+    // ...
41
+}
42
+else if(tracker.is('pointer-tracker')) {
43
+    // tracker is inferred to be a PointerTracker
44
+    // ...
45
+}
46
+else {
47
+    // ...
48
+}
49
+```

+ 1
- 1
docs/hooks.py 파일 보기

@@ -11,7 +11,7 @@ def copy_static_files(config, **kwargs):
11 11
 def copy_directory(dir_path, site_dir):
12 12
     d = os.path.join(site_dir, dir_path)
13 13
     os.makedirs(d, exist_ok=True)
14
-    s = dir_path if dir_path != "dist" else "www/dist"
14
+    s = dir_path if dir_path != "dist" else "build/dist"
15 15
     copy_tree(s, d)
16 16
 
17 17
 def copy_tree(src, dst, symlinks=False, ignore=None):

+ 1
- 1
esbuild.mjs 파일 보기

@@ -29,7 +29,7 @@ const options = {
29 29
     legalComments: 'inline',
30 30
     banner: { js: generateBanner() },
31 31
     footer: { js: serve ? generateLiveReloadCode() : '' },
32
-    outfile: 'www/dist/' + (minify ? 'encantar.min.js' : 'encantar.js'),
32
+    outfile: 'build/dist/' + (minify ? 'encantar.min.js' : 'encantar.js'),
33 33
     sourcemap: !production && 'linked',
34 34
     logLevel: 'info',
35 35
 };

+ 7
- 393
package-lock.json 파일 보기

@@ -9,7 +9,7 @@
9 9
       "version": "0.4.4-dev",
10 10
       "license": "LGPL-3.0-or-later",
11 11
       "dependencies": {
12
-        "speedy-vision": "github:alemart/speedy-vision#v0.9.1"
12
+        "speedy-vision": "github:alemart/speedy-vision#af1a64017ea1476fdac1adbbba4337732e5bfefb"
13 13
       },
14 14
       "devDependencies": {
15 15
         "esbuild": "0.24.2",
@@ -19,270 +19,13 @@
19 19
         "url": "https://github.com/sponsors/alemart"
20 20
       }
21 21
     },
22
-    "node_modules/@esbuild/aix-ppc64": {
23
-      "version": "0.24.2",
24
-      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.2.tgz",
25
-      "integrity": "sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==",
26
-      "cpu": [
27
-        "ppc64"
28
-      ],
29
-      "dev": true,
30
-      "optional": true,
31
-      "os": [
32
-        "aix"
33
-      ],
34
-      "engines": {
35
-        "node": ">=18"
36
-      }
37
-    },
38
-    "node_modules/@esbuild/android-arm": {
39
-      "version": "0.24.2",
40
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.2.tgz",
41
-      "integrity": "sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==",
42
-      "cpu": [
43
-        "arm"
44
-      ],
45
-      "dev": true,
46
-      "optional": true,
47
-      "os": [
48
-        "android"
49
-      ],
50
-      "engines": {
51
-        "node": ">=18"
52
-      }
53
-    },
54
-    "node_modules/@esbuild/android-arm64": {
55
-      "version": "0.24.2",
56
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.2.tgz",
57
-      "integrity": "sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==",
58
-      "cpu": [
59
-        "arm64"
60
-      ],
61
-      "dev": true,
62
-      "optional": true,
63
-      "os": [
64
-        "android"
65
-      ],
66
-      "engines": {
67
-        "node": ">=18"
68
-      }
69
-    },
70
-    "node_modules/@esbuild/android-x64": {
71
-      "version": "0.24.2",
72
-      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.2.tgz",
73
-      "integrity": "sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==",
74
-      "cpu": [
75
-        "x64"
76
-      ],
77
-      "dev": true,
78
-      "optional": true,
79
-      "os": [
80
-        "android"
81
-      ],
82
-      "engines": {
83
-        "node": ">=18"
84
-      }
85
-    },
86
-    "node_modules/@esbuild/darwin-arm64": {
87
-      "version": "0.24.2",
88
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.2.tgz",
89
-      "integrity": "sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==",
90
-      "cpu": [
91
-        "arm64"
92
-      ],
93
-      "dev": true,
94
-      "optional": true,
95
-      "os": [
96
-        "darwin"
97
-      ],
98
-      "engines": {
99
-        "node": ">=18"
100
-      }
101
-    },
102
-    "node_modules/@esbuild/darwin-x64": {
103
-      "version": "0.24.2",
104
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.2.tgz",
105
-      "integrity": "sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==",
106
-      "cpu": [
107
-        "x64"
108
-      ],
109
-      "dev": true,
110
-      "optional": true,
111
-      "os": [
112
-        "darwin"
113
-      ],
114
-      "engines": {
115
-        "node": ">=18"
116
-      }
117
-    },
118
-    "node_modules/@esbuild/freebsd-arm64": {
119
-      "version": "0.24.2",
120
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.2.tgz",
121
-      "integrity": "sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==",
122
-      "cpu": [
123
-        "arm64"
124
-      ],
125
-      "dev": true,
126
-      "optional": true,
127
-      "os": [
128
-        "freebsd"
129
-      ],
130
-      "engines": {
131
-        "node": ">=18"
132
-      }
133
-    },
134
-    "node_modules/@esbuild/freebsd-x64": {
135
-      "version": "0.24.2",
136
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.2.tgz",
137
-      "integrity": "sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==",
138
-      "cpu": [
139
-        "x64"
140
-      ],
141
-      "dev": true,
142
-      "optional": true,
143
-      "os": [
144
-        "freebsd"
145
-      ],
146
-      "engines": {
147
-        "node": ">=18"
148
-      }
149
-    },
150
-    "node_modules/@esbuild/linux-arm": {
151
-      "version": "0.24.2",
152
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.2.tgz",
153
-      "integrity": "sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==",
154
-      "cpu": [
155
-        "arm"
156
-      ],
157
-      "dev": true,
158
-      "optional": true,
159
-      "os": [
160
-        "linux"
161
-      ],
162
-      "engines": {
163
-        "node": ">=18"
164
-      }
165
-    },
166
-    "node_modules/@esbuild/linux-arm64": {
167
-      "version": "0.24.2",
168
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.2.tgz",
169
-      "integrity": "sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==",
170
-      "cpu": [
171
-        "arm64"
172
-      ],
173
-      "dev": true,
174
-      "optional": true,
175
-      "os": [
176
-        "linux"
177
-      ],
178
-      "engines": {
179
-        "node": ">=18"
180
-      }
181
-    },
182
-    "node_modules/@esbuild/linux-ia32": {
183
-      "version": "0.24.2",
184
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.2.tgz",
185
-      "integrity": "sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==",
186
-      "cpu": [
187
-        "ia32"
188
-      ],
189
-      "dev": true,
190
-      "optional": true,
191
-      "os": [
192
-        "linux"
193
-      ],
194
-      "engines": {
195
-        "node": ">=18"
196
-      }
197
-    },
198
-    "node_modules/@esbuild/linux-loong64": {
199
-      "version": "0.24.2",
200
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.2.tgz",
201
-      "integrity": "sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==",
202
-      "cpu": [
203
-        "loong64"
204
-      ],
205
-      "dev": true,
206
-      "optional": true,
207
-      "os": [
208
-        "linux"
209
-      ],
210
-      "engines": {
211
-        "node": ">=18"
212
-      }
213
-    },
214
-    "node_modules/@esbuild/linux-mips64el": {
215
-      "version": "0.24.2",
216
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.2.tgz",
217
-      "integrity": "sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==",
218
-      "cpu": [
219
-        "mips64el"
220
-      ],
221
-      "dev": true,
222
-      "optional": true,
223
-      "os": [
224
-        "linux"
225
-      ],
226
-      "engines": {
227
-        "node": ">=18"
228
-      }
229
-    },
230
-    "node_modules/@esbuild/linux-ppc64": {
231
-      "version": "0.24.2",
232
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.2.tgz",
233
-      "integrity": "sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==",
234
-      "cpu": [
235
-        "ppc64"
236
-      ],
237
-      "dev": true,
238
-      "optional": true,
239
-      "os": [
240
-        "linux"
241
-      ],
242
-      "engines": {
243
-        "node": ">=18"
244
-      }
245
-    },
246
-    "node_modules/@esbuild/linux-riscv64": {
247
-      "version": "0.24.2",
248
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.2.tgz",
249
-      "integrity": "sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==",
250
-      "cpu": [
251
-        "riscv64"
252
-      ],
253
-      "dev": true,
254
-      "optional": true,
255
-      "os": [
256
-        "linux"
257
-      ],
258
-      "engines": {
259
-        "node": ">=18"
260
-      }
261
-    },
262
-    "node_modules/@esbuild/linux-s390x": {
263
-      "version": "0.24.2",
264
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.2.tgz",
265
-      "integrity": "sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==",
266
-      "cpu": [
267
-        "s390x"
268
-      ],
269
-      "dev": true,
270
-      "optional": true,
271
-      "os": [
272
-        "linux"
273
-      ],
274
-      "engines": {
275
-        "node": ">=18"
276
-      }
277
-    },
278 22
     "node_modules/@esbuild/linux-x64": {
279 23
       "version": "0.24.2",
280
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.2.tgz",
281
-      "integrity": "sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==",
282 24
       "cpu": [
283 25
         "x64"
284 26
       ],
285 27
       "dev": true,
28
+      "license": "MIT",
286 29
       "optional": true,
287 30
       "os": [
288 31
         "linux"
@@ -291,140 +34,11 @@
291 34
         "node": ">=18"
292 35
       }
293 36
     },
294
-    "node_modules/@esbuild/netbsd-arm64": {
295
-      "version": "0.24.2",
296
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.24.2.tgz",
297
-      "integrity": "sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==",
298
-      "cpu": [
299
-        "arm64"
300
-      ],
301
-      "dev": true,
302
-      "optional": true,
303
-      "os": [
304
-        "netbsd"
305
-      ],
306
-      "engines": {
307
-        "node": ">=18"
308
-      }
309
-    },
310
-    "node_modules/@esbuild/netbsd-x64": {
311
-      "version": "0.24.2",
312
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.2.tgz",
313
-      "integrity": "sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==",
314
-      "cpu": [
315
-        "x64"
316
-      ],
317
-      "dev": true,
318
-      "optional": true,
319
-      "os": [
320
-        "netbsd"
321
-      ],
322
-      "engines": {
323
-        "node": ">=18"
324
-      }
325
-    },
326
-    "node_modules/@esbuild/openbsd-arm64": {
327
-      "version": "0.24.2",
328
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.2.tgz",
329
-      "integrity": "sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==",
330
-      "cpu": [
331
-        "arm64"
332
-      ],
333
-      "dev": true,
334
-      "optional": true,
335
-      "os": [
336
-        "openbsd"
337
-      ],
338
-      "engines": {
339
-        "node": ">=18"
340
-      }
341
-    },
342
-    "node_modules/@esbuild/openbsd-x64": {
343
-      "version": "0.24.2",
344
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.2.tgz",
345
-      "integrity": "sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==",
346
-      "cpu": [
347
-        "x64"
348
-      ],
349
-      "dev": true,
350
-      "optional": true,
351
-      "os": [
352
-        "openbsd"
353
-      ],
354
-      "engines": {
355
-        "node": ">=18"
356
-      }
357
-    },
358
-    "node_modules/@esbuild/sunos-x64": {
359
-      "version": "0.24.2",
360
-      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.2.tgz",
361
-      "integrity": "sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==",
362
-      "cpu": [
363
-        "x64"
364
-      ],
365
-      "dev": true,
366
-      "optional": true,
367
-      "os": [
368
-        "sunos"
369
-      ],
370
-      "engines": {
371
-        "node": ">=18"
372
-      }
373
-    },
374
-    "node_modules/@esbuild/win32-arm64": {
375
-      "version": "0.24.2",
376
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.2.tgz",
377
-      "integrity": "sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==",
378
-      "cpu": [
379
-        "arm64"
380
-      ],
381
-      "dev": true,
382
-      "optional": true,
383
-      "os": [
384
-        "win32"
385
-      ],
386
-      "engines": {
387
-        "node": ">=18"
388
-      }
389
-    },
390
-    "node_modules/@esbuild/win32-ia32": {
391
-      "version": "0.24.2",
392
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.2.tgz",
393
-      "integrity": "sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==",
394
-      "cpu": [
395
-        "ia32"
396
-      ],
397
-      "dev": true,
398
-      "optional": true,
399
-      "os": [
400
-        "win32"
401
-      ],
402
-      "engines": {
403
-        "node": ">=18"
404
-      }
405
-    },
406
-    "node_modules/@esbuild/win32-x64": {
407
-      "version": "0.24.2",
408
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.2.tgz",
409
-      "integrity": "sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==",
410
-      "cpu": [
411
-        "x64"
412
-      ],
413
-      "dev": true,
414
-      "optional": true,
415
-      "os": [
416
-        "win32"
417
-      ],
418
-      "engines": {
419
-        "node": ">=18"
420
-      }
421
-    },
422 37
     "node_modules/esbuild": {
423 38
       "version": "0.24.2",
424
-      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.2.tgz",
425
-      "integrity": "sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==",
426 39
       "dev": true,
427 40
       "hasInstallScript": true,
41
+      "license": "MIT",
428 42
       "bin": {
429 43
         "esbuild": "bin/esbuild"
430 44
       },
@@ -460,17 +74,17 @@
460 74
       }
461 75
     },
462 76
     "node_modules/speedy-vision": {
463
-      "version": "0.9.1",
464
-      "resolved": "git+ssh://git@github.com/alemart/speedy-vision.git#6a48fca4c45b6f4c80bfa8bcacbed5abd0e69ec2",
77
+      "version": "0.9.1.1",
78
+      "resolved": "git+ssh://git@github.com/alemart/speedy-vision.git#af1a64017ea1476fdac1adbbba4337732e5bfefb",
79
+      "integrity": "sha512-d6iK96sKp8fazja1F/pK8Ymt6kN21IMk39xuypuiInIAlirlQVW2//zXkIDxejunIwB61wYwxtddWLk+4s7D1w==",
465 80
       "funding": {
466 81
         "url": "https://github.com/sponsors/alemart"
467 82
       }
468 83
     },
469 84
     "node_modules/typescript": {
470 85
       "version": "4.9.5",
471
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
472
-      "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
473 86
       "dev": true,
87
+      "license": "Apache-2.0",
474 88
       "bin": {
475 89
         "tsc": "bin/tsc",
476 90
         "tsserver": "bin/tsserver"

+ 7
- 4
package.json 파일 보기

@@ -28,19 +28,22 @@
28 28
   ],
29 29
   "type": "module",
30 30
   "main": "src/main.ts",
31
+  "types": "build/types/main.d.ts",
31 32
   "scripts": {
32 33
     "start": "node esbuild.mjs --minify --serve",
33 34
     "prebuild": "tsc --noEmit && npm run clean",
34
-    "build": "node esbuild.mjs && node esbuild.mjs --minify",
35
-    "plugins": "for f in $(find plugins/ -name *.js); do esbuild --minify < $f > ${f%.*}.min.js; done",
35
+    "build": "mkdir -p build/dist && node esbuild.mjs && node esbuild.mjs --minify",
36
+    "build-types": "mkdir -p build/types && tsc --emitDeclarationOnly --declaration --declarationDir build/types",
37
+    "build-bundle-of-types": "mkdir -p build/dist && tsc --emitDeclarationOnly --isolatedModules false --declaration --outFile build/dist/encantar.d.ts",
38
+    "build-plugins": "mkdir -p build/plugins && for f in $(find plugins/ -name *.js); do esbuild --minify < $f > build/${f%.*}.min.js; done",
36 39
     "update": "npm update speedy-vision",
37 40
     "deploy": "mkdocs gh-deploy",
38 41
     "docs": "mkdocs serve",
39
-    "clean": "rm -rf www/dist/*.*",
42
+    "clean": "rm -rf build/",
40 43
     "test": "echo \"Error: no test specified\" && exit 1"
41 44
   },
42 45
   "dependencies": {
43
-    "speedy-vision": "github:alemart/speedy-vision#v0.9.1"
46
+    "speedy-vision": "github:alemart/speedy-vision#af1a64017ea1476fdac1adbbba4337732e5bfefb"
44 47
   },
45 48
   "devDependencies": {
46 49
     "esbuild": "0.24.2",

+ 3
- 3
plugins/aframe-with-encantar.js 파일 보기

@@ -107,7 +107,7 @@ const Utils = () => ({
107 107
             return null;
108 108
 
109 109
         for(const result of frame.results) {
110
-            if(result.tracker.type == 'image-tracker') {
110
+            if(result.of('image-tracker')) {
111 111
                 for(const trackable of result.trackables) {
112 112
                     if(name === '' || name === trackable.referenceImage.name) {
113 113
                         return {
@@ -129,7 +129,7 @@ const Utils = () => ({
129 129
             return null;
130 130
 
131 131
         for(const result of frame.results) {
132
-            if(result.tracker.type == 'image-tracker') {
132
+            if(result.of('image-tracker')) {
133 133
                 if(result.trackables.length > 0)
134 134
                     return result.viewer;
135 135
             }
@@ -144,7 +144,7 @@ const Utils = () => ({
144 144
             return [];
145 145
 
146 146
         for(const result of frame.results) {
147
-            if(result.tracker.type == 'pointer-tracker')
147
+            if(result.of('pointer-tracker'))
148 148
                 return result.trackables;
149 149
         }
150 150
 

+ 2
- 2
plugins/babylon-with-encantar.js 파일 보기

@@ -268,7 +268,7 @@ function encantar(demo)
268 268
         ar._pointers.length = 0;
269 269
 
270 270
         for(const result of frame.results) {
271
-            if(result.tracker.type == 'image-tracker') {
271
+            if(result.of('image-tracker')) {
272 272
                 if(result.trackables.length > 0) {
273 273
                     const trackable = result.trackables[0];
274 274
                     const projectionMatrix = result.viewer.view.projectionMatrix;
@@ -282,7 +282,7 @@ function encantar(demo)
282 282
                     found = true;
283 283
                 }
284 284
             }
285
-            else if(result.tracker.type == 'pointer-tracker') {
285
+            else if(result.of('pointer-tracker')) {
286 286
                 if(result.trackables.length > 0)
287 287
                     ar._pointers.push.apply(ar._pointers, result.trackables);
288 288
             }

+ 2
- 2
plugins/three-with-encantar.js 파일 보기

@@ -262,7 +262,7 @@ export function encantar(demo)
262 262
         ar._pointers.length = 0;
263 263
 
264 264
         for(const result of frame.results) {
265
-            if(result.tracker.type == 'image-tracker') {
265
+            if(result.of('image-tracker')) {
266 266
                 if(result.trackables.length > 0) {
267 267
                     const trackable = result.trackables[0];
268 268
                     const projectionMatrix = result.viewer.view.projectionMatrix;
@@ -276,7 +276,7 @@ export function encantar(demo)
276 276
                     found = true;
277 277
                 }
278 278
             }
279
-            else if(result.tracker.type == 'pointer-tracker') {
279
+            else if(result.of('pointer-tracker')) {
280 280
                 if(result.trackables.length > 0)
281 281
                     ar._pointers.push.apply(ar._pointers, result.trackables);
282 282
             }

+ 24
- 10
src/core/session.ts 파일 보기

@@ -33,7 +33,7 @@ import { Settings } from './settings';
33 33
 import { Stats } from './stats';
34 34
 import { Gizmos } from '../ui/gizmos';
35 35
 import { Frame } from './frame';
36
-import { Tracker } from '../trackers/tracker';
36
+import { Trackable, Tracker, TrackerResult } from '../trackers/tracker';
37 37
 import { TimeManager } from './time-manager';
38 38
 import { Source } from '../sources/source';
39 39
 import { VideoSource } from '../sources/video-source';
@@ -87,13 +87,28 @@ const DEFAULT_OPTIONS: Readonly<Required<SessionOptions>> = {
87 87
     gizmos: false,
88 88
 };
89 89
 
90
+/** Helper class */
91
+class EmptyTrackerResult extends TrackerResult
92
+{
93
+    readonly tracker: Tracker;
94
+    readonly trackables: Trackable[];
95
+
96
+    constructor(tracker: Tracker)
97
+    {
98
+        super();
99
+        this.tracker = tracker;
100
+        this.trackables = [];
101
+    }
102
+}
103
+
104
+
90 105
 
91 106
 
92 107
 /**
93 108
  * A Session represents an intent to display AR content
94 109
  * and encapsulates the main loop (update-render cycle)
95 110
  */
96
-export class Session extends AREventTarget<SessionEventType>
111
+export class Session extends AREventTarget<SessionEvent>
97 112
 {
98 113
     /** Number of active sessions */
99 114
     private static _count = 0;
@@ -514,12 +529,14 @@ export class Session extends AREventTarget<SessionEventType>
514 529
     {
515 530
         // prefer video sources
516 531
         for(let i = 0; i < sources.length; i++) {
517
-            if(sources[i]._type == 'video')
518
-                return sources[i] as VideoSource;
532
+            const source = sources[i];
533
+            if(source._is('video'))
534
+                return source;
519 535
         }
520 536
         for(let i = 0; i < sources.length; i++) {
521
-            if(sources[i]._type == 'canvas')
522
-                return sources[i] as CanvasSource;
537
+            const source = sources[i];
538
+            if(source._is('canvas'))
539
+                return source;
523 540
         }
524 541
 
525 542
         // emit warning
@@ -705,10 +722,7 @@ export class Session extends AREventTarget<SessionEventType>
705 722
 
706 723
                 // create a frame
707 724
                 const results = this._trackers.map(tracker =>
708
-                    tracker._output.exports || ({
709
-                        tracker: tracker,
710
-                        trackables: [],
711
-                    })
725
+                    tracker._output.exports || new EmptyTrackerResult(tracker)
712 726
                 );
713 727
                 const frame = new Frame(this, results);
714 728
 

+ 5
- 7
src/core/viewport.ts 파일 보기

@@ -46,13 +46,10 @@ type ViewportSizeGetter = () => SpeedySize;
46 46
 type ViewportEventType = 'resize' | 'fullscreenchange';
47 47
 
48 48
 /** An event emitted by a Viewport */
49
-class ViewportEvent extends AREvent<ViewportEventType> { }
50
-
51
-/** Viewport event target */
52
-class ViewportEventTarget extends AREventTarget<ViewportEventType> { }
49
+export class ViewportEvent extends AREvent<ViewportEventType> { }
53 50
 
54 51
 /** Viewport style (immersive mode) */
55
-type ViewportStyle = 'best-fit' | 'stretch' | 'crop' | 'inline';
52
+export type ViewportStyle = 'best-fit' | 'stretch' | 'crop' | 'inline';
56 53
 
57 54
 
58 55
 
@@ -704,8 +701,9 @@ class ViewportResizer
704 701
 
705 702
     /**
706 703
      * Called when the viewport receives a 'resize' event
704
+     * @param event
707 705
      */
708
-    private _onViewportResize(): void
706
+    private _onViewportResize(event: ViewportEvent): void
709 707
     {
710 708
         const viewport = this._viewport;
711 709
 
@@ -948,7 +946,7 @@ class CropResizeStrategy extends ImmersiveResizeStrategy
948 946
 /**
949 947
  * Viewport
950 948
  */
951
-export class Viewport extends ViewportEventTarget
949
+export class Viewport extends AREventTarget<ViewportEvent>
952 950
 {
953 951
     /** Viewport resolution (controls the size of the drawing buffer of the foreground canvas) */
954 952
     private readonly _resolution: Resolution;

+ 11
- 2
src/sources/canvas-source.ts 파일 보기

@@ -25,7 +25,7 @@ import { SpeedyMedia } from 'speedy-vision/types/core/speedy-media';
25 25
 import { SpeedyPromise } from 'speedy-vision/types/core/speedy-promise';
26 26
 import { Utils, Nullable } from '../utils/utils';
27 27
 import { IllegalOperationError } from '../utils/errors';
28
-import { Source } from './source';
28
+import { Source, SourceType } from './source';
29 29
 
30 30
 /**
31 31
  * HTMLCanvasElement-based source of data
@@ -63,12 +63,21 @@ export class CanvasSource implements Source
63 63
      * A type-identifier of the source of data
64 64
      * @internal
65 65
      */
66
-    get _type(): string
66
+    get _type(): keyof SourceType
67 67
     {
68 68
         return 'canvas';
69 69
     }
70 70
 
71 71
     /**
72
+     * Check if this source is of a certain type
73
+     * @internal
74
+     */
75
+    _is<T extends keyof SourceType>(type: T): this is SourceType[T]
76
+    {
77
+        return type === this._type;
78
+    }
79
+
80
+    /**
72 81
      * Get media
73 82
      * @internal
74 83
      */

+ 11
- 2
src/sources/pointer-source.ts 파일 보기

@@ -22,7 +22,7 @@
22 22
 
23 23
 import Speedy from 'speedy-vision';
24 24
 import { SpeedyPromise } from 'speedy-vision/types/core/speedy-promise';
25
-import { Source } from './source';
25
+import { Source, SourceType } from './source';
26 26
 import { Viewport } from '../core/viewport'
27 27
 import { Utils, Nullable } from '../utils/utils';
28 28
 
@@ -55,12 +55,21 @@ export class PointerSource implements Source
55 55
      * A type-identifier of the source of data
56 56
      * @internal
57 57
      */
58
-    get _type(): string
58
+    get _type(): keyof SourceType
59 59
     {
60 60
         return 'pointer-source';
61 61
     }
62 62
 
63 63
     /**
64
+     * Check if this source is of a certain type
65
+     * @internal
66
+     */
67
+    _is<T extends keyof SourceType>(type: T): this is SourceType[T]
68
+    {
69
+        return type === this._type;
70
+    }
71
+
72
+    /**
64 73
      * Consume a pointer event
65 74
      * @returns the next pointer event to be consumed, or null if there are none
66 75
      * @internal

+ 18
- 2
src/sources/source.ts 파일 보기

@@ -21,6 +21,9 @@
21 21
  */
22 22
 
23 23
 import { SpeedyPromise } from 'speedy-vision/types/core/speedy-promise';
24
+import { CanvasSource } from './canvas-source';
25
+import { PointerSource } from './pointer-source';
26
+import { VideoSource } from './video-source';
24 27
 
25 28
 /**
26 29
  * Abstract source of data
@@ -28,7 +31,10 @@ import { SpeedyPromise } from 'speedy-vision/types/core/speedy-promise';
28 31
 export interface Source
29 32
 {
30 33
     /** @internal type-identifier of the source of data */
31
-    readonly _type: string;
34
+    readonly _type: keyof SourceType;
35
+
36
+    /** @internal check if this source is of a certain type */
37
+    _is<T extends keyof SourceType>(type: T): this is SourceType[T];
32 38
 
33 39
     /** @internal method to initialize the source of data (gets the data ready) */
34 40
     _init(): SpeedyPromise<void>;
@@ -38,4 +44,14 @@ export interface Source
38 44
 
39 45
     /** @internal stats related to this source of data */
40 46
     readonly _stats: string;
41
-}
47
+}
48
+
49
+/**
50
+ * A helper for type-narrowing
51
+ * @internal
52
+ */
53
+export type SourceType = {
54
+    'video': VideoSource,
55
+    'canvas': CanvasSource,
56
+    'pointer-source': PointerSource
57
+};

+ 11
- 2
src/sources/video-source.ts 파일 보기

@@ -25,7 +25,7 @@ import { SpeedyMedia } from 'speedy-vision/types/core/speedy-media';
25 25
 import { SpeedyPromise } from 'speedy-vision/types/core/speedy-promise';
26 26
 import { Utils, Nullable } from '../utils/utils';
27 27
 import { IllegalOperationError, NotSupportedError, TimeoutError } from '../utils/errors';
28
-import { Source } from './source';
28
+import { Source, SourceType } from './source';
29 29
 
30 30
 /** A message to be displayed if a video can't autoplay and user interaction is required */
31 31
 const ALERT_MESSAGE = 'Tap on the screen to start';
@@ -70,12 +70,21 @@ export class VideoSource implements Source
70 70
      * A type-identifier of the source of data
71 71
      * @internal
72 72
      */
73
-    get _type(): string
73
+    get _type(): keyof SourceType
74 74
     {
75 75
         return 'video';
76 76
     }
77 77
 
78 78
     /**
79
+     * Check if this source is of a certain type
80
+     * @internal
81
+     */
82
+    _is<T extends keyof SourceType>(type: T): this is SourceType[T]
83
+    {
84
+        return type === this._type;
85
+    }
86
+
87
+    /**
79 88
      * Get media
80 89
      * @internal
81 90
      */

+ 31
- 8
src/trackers/image-tracker/image-tracker.ts 파일 보기

@@ -33,7 +33,7 @@ import { SpeedyPipelineNodeFASTKeypointDetector } from 'speedy-vision/types/core
33 33
 import { SpeedyKeypoint } from 'speedy-vision/types/core/speedy-keypoint';
34 34
 import { VideoSource } from '../../sources/video-source';
35 35
 import { CanvasSource } from '../../sources/canvas-source';
36
-import { Tracker, TrackerOutput, TrackerResult, Trackable } from '../tracker';
36
+import { Tracker, TrackerOutput, TrackerResult, Trackable, TrackerType, TrackerResultType } from '../tracker';
37 37
 import { Session } from '../../core/session';
38 38
 import { IllegalOperationError, IllegalArgumentError } from '../../utils/errors';
39 39
 import { Resolution } from '../../utils/resolution';
@@ -65,7 +65,7 @@ export interface TrackableImage extends Trackable
65 65
 }
66 66
 
67 67
 /** Image Tracker result to be consumed by the user */
68
-export interface ImageTrackerResult extends TrackerResult
68
+export class ImageTrackerResult extends TrackerResult
69 69
 {
70 70
     /** tracker */
71 71
     readonly tracker: ImageTracker;
@@ -75,6 +75,20 @@ export interface ImageTrackerResult extends TrackerResult
75 75
 
76 76
     /** 3D virtual camera */
77 77
     readonly viewer: Viewer;
78
+
79
+    /**
80
+     * Constructor
81
+     * @param tracker
82
+     * @param trackables
83
+     * @param viewer
84
+     */
85
+    constructor(tracker: ImageTracker, trackables: TrackableImage[], viewer: Viewer)
86
+    {
87
+        super();
88
+        this.tracker = tracker;
89
+        this.trackables = trackables;
90
+        this.viewer = viewer;
91
+    }
78 92
 }
79 93
 
80 94
 /** Image Tracker output */
@@ -119,7 +133,7 @@ const DEFAULT_OPTIONS: Readonly<ImageTrackerOptions> = {
119 133
 /**
120 134
  * The ImageTracker tracks an image (one at a time)
121 135
  */
122
-export class ImageTracker extends AREventTarget<ImageTrackerEventType> implements Tracker
136
+export class ImageTracker extends AREventTarget<ImageTrackerEvent> implements Tracker
123 137
 {
124 138
     /** session */
125 139
     private _session: Nullable<Session>;
@@ -176,13 +190,22 @@ export class ImageTracker extends AREventTarget<ImageTrackerEventType> implement
176 190
 
177 191
     /**
178 192
      * The type of the tracker
193
+     * @deprecated
179 194
      */
180
-    get type(): string
195
+    get type(): keyof TrackerType
181 196
     {
182 197
         return 'image-tracker';
183 198
     }
184 199
 
185 200
     /**
201
+     * Check if this tracker is of a certain type
202
+     */
203
+    is<T extends keyof TrackerType>(type: T): this is TrackerType[T]
204
+    {
205
+        return type === this.type;
206
+    }
207
+
208
+    /**
186 209
      * Current state name
187 210
      */
188 211
     get state(): ImageTrackerStateName
@@ -261,12 +284,12 @@ export class ImageTracker extends AREventTarget<ImageTrackerEventType> implement
261 284
         // XXX also let the user specify a source manually?
262 285
         for(const source of session.sources) {
263 286
             // prefer video sources
264
-            if(source._type == 'video') {
265
-                this._source = source as VideoSource;
287
+            if(source._is('video')) {
288
+                this._source = source;
266 289
                 break;
267 290
             }
268
-            else if(source._type == 'canvas')
269
-                this._source = source as CanvasSource;
291
+            else if(source._is('canvas'))
292
+                this._source = source;
270 293
         }
271 294
         if(this._source === null)
272 295
             throw new IllegalOperationError('The image tracker requires a suitable source of data');

+ 5
- 5
src/trackers/image-tracker/states/tracking.ts 파일 보기

@@ -433,11 +433,11 @@ export class ImageTrackerTrackingState extends ImageTrackerState
433 433
             };
434 434
 
435 435
             // the result generated by the image tracker
436
-            const result: ImageTrackerResult = {
437
-                tracker: this._imageTracker,
438
-                trackables: [ trackable ],
439
-                viewer: viewer
440
-            };
436
+            const result = new ImageTrackerResult(
437
+                this._imageTracker,
438
+                [ trackable ],
439
+                viewer
440
+            );
441 441
 
442 442
             // tracker output
443 443
             const trackerOutput: ImageTrackerOutput = {

+ 28
- 11
src/trackers/pointer-tracker/pointer-tracker.ts 파일 보기

@@ -22,7 +22,7 @@
22 22
 
23 23
 import Speedy from 'speedy-vision';
24 24
 import { SpeedyPromise } from 'speedy-vision/types/core/speedy-promise';
25
-import { TrackerResult, TrackerOutput, Tracker } from '../tracker';
25
+import { TrackerResult, TrackerOutput, Tracker, TrackerType } from '../tracker';
26 26
 import { TrackablePointer, TrackablePointerPhase } from './trackable-pointer';
27 27
 import { PointerSource } from '../../sources/pointer-source';
28 28
 import { Vector2 } from '../../geometry/vector2';
@@ -34,13 +34,25 @@ import { Viewport } from '../../core/viewport';
34 34
 /**
35 35
  * A result of a PointerTracker. It's meant to be consumed by the user/application
36 36
  */
37
-export interface PointerTrackerResult extends TrackerResult
37
+export class PointerTrackerResult extends TrackerResult
38 38
 {
39 39
     /** the tracker that generated this result */
40 40
     readonly tracker: PointerTracker;
41 41
 
42 42
     /** the trackables */
43 43
     readonly trackables: TrackablePointer[];
44
+
45
+    /**
46
+     * Constructor
47
+     * @param tracker
48
+     * @param trackables
49
+     */
50
+    constructor(tracker: PointerTracker, trackables: TrackablePointer[])
51
+    {
52
+        super();
53
+        this.tracker = tracker;
54
+        this.trackables = trackables;
55
+    }
44 56
 }
45 57
 
46 58
 /**
@@ -187,13 +199,22 @@ export class PointerTracker implements Tracker
187 199
 
188 200
     /**
189 201
      * The type of the tracker
202
+     * @deprecated
190 203
      */
191
-    get type(): string
204
+    get type(): keyof TrackerType
192 205
     {
193 206
         return 'pointer-tracker';
194 207
     }
195 208
 
196 209
     /**
210
+     * Check if this tracker is of a certain type
211
+     */
212
+    is<T extends keyof TrackerType>(type: T): this is TrackerType[T]
213
+    {
214
+        return type === this.type;
215
+    }
216
+
217
+    /**
197 218
      * Initialize the tracker
198 219
      * @param session
199 220
      * @returns a promise that is resolved as soon as the tracker is initialized
@@ -208,8 +229,8 @@ export class PointerTracker implements Tracker
208 229
 
209 230
         // find the pointer source
210 231
         for(const source of session.sources) {
211
-            if(source._type == 'pointer-source') {
212
-                this._source = source as PointerSource;
232
+            if(source._is('pointer-source')) {
233
+                this._source = source;
213 234
                 break;
214 235
             }
215 236
         }
@@ -470,12 +491,8 @@ export class PointerTracker implements Tracker
470 491
         const trackables: TrackablePointer[] = [];
471 492
         this._activePointers.forEach(trackable => trackables.push(trackable));
472 493
 
473
-        return {
474
-            exports: {
475
-                tracker: this,
476
-                trackables: this._sortTrackables(trackables)
477
-            }
478
-        };
494
+        const result = new PointerTrackerResult(this, this._sortTrackables(trackables));
495
+        return { exports: result };
479 496
     }
480 497
 
481 498
     /**

+ 38
- 9
src/trackers/tracker.ts 파일 보기

@@ -23,6 +23,8 @@
23 23
 import { Session } from '../core/session';
24 24
 import { SpeedyPromise } from 'speedy-vision/types/core/speedy-promise';
25 25
 import { SpeedyMedia } from 'speedy-vision/types/core/speedy-media';
26
+import { ImageTracker, ImageTrackerResult } from './image-tracker/image-tracker';
27
+import { PointerTracker, PointerTrackerResult } from './pointer-tracker/pointer-tracker';
26 28
 
27 29
 /**
28 30
  * A Trackable is something that can be tracked
@@ -37,13 +39,19 @@ export interface Trackable
37 39
  * The result of a Tracker in a particular frame of a session. Such result is
38 40
  * meant to be consumed by the user/application.
39 41
  */
40
-export interface TrackerResult
42
+export abstract class TrackerResult
41 43
 {
42 44
     /** the tracker that generated this result */
43
-    readonly tracker: Tracker;
45
+    abstract readonly tracker: Tracker;
44 46
 
45 47
     /** an array of trackables (possibly empty) */
46
-    readonly trackables: Trackable[];
48
+    abstract readonly trackables: Trackable[];
49
+
50
+    /** check if this result was generated by a tracker of a certain type */
51
+    of<T extends keyof TrackerResultType>(trackerType: T): this is TrackerResultType[T]
52
+    {
53
+        return this.tracker.is(trackerType);
54
+    }
47 55
 }
48 56
 
49 57
 /**
@@ -63,21 +71,42 @@ export interface TrackerOutput
63 71
  */
64 72
 export interface Tracker
65 73
 {
66
-    /** a string that identifies the type of the tracker */
67
-    readonly type: string;
74
+    /** check if this tracker is of a certain type */
75
+    is<T extends keyof TrackerType>(type: T): this is TrackerType[T];
76
+
77
+    /** a string that identifies the type of the tracker @deprecated */
78
+    readonly type: keyof TrackerType;
68 79
 
69 80
     /** initialize tracker @internal */
70
-    _init: (session: Session) => SpeedyPromise<void>;
81
+    _init(session: Session): SpeedyPromise<void>;
71 82
 
72 83
     /** release resources @internal */
73
-    _release: () => SpeedyPromise<void>;
84
+    _release(): SpeedyPromise<void>;
74 85
 
75 86
     /** update cycle @internal */
76
-    _update: () => SpeedyPromise<void>;
87
+    _update(): SpeedyPromise<void>;
77 88
 
78 89
     /** output of the last frame @internal */
79 90
     readonly _output: TrackerOutput;
80 91
 
81 92
     /** stats related to this tracker @internal */
82 93
     readonly _stats: string;
83
-}
94
+}
95
+
96
+/**
97
+ * A helper for type-narrowing
98
+ * @internal
99
+ */
100
+export type TrackerType = {
101
+    'image-tracker': ImageTracker,
102
+    'pointer-tracker': PointerTracker
103
+};
104
+
105
+/**
106
+ * A helper for type-narrowing
107
+ * @internal
108
+ */
109
+export type TrackerResultType = {
110
+    'image-tracker': ImageTrackerResult,
111
+    'pointer-tracker': PointerTrackerResult
112
+};

+ 5
- 7
src/ui/fullscreen-button.ts 파일 보기

@@ -20,7 +20,7 @@
20 20
  * A built-in fullscreen button introduced as a convenience
21 21
  */
22 22
 
23
-import { Viewport } from '../core/viewport';
23
+import { Viewport, ViewportEvent } from '../core/viewport';
24 24
 
25 25
 /** Button icon to be displayed when the fullscreen mode is disabled */
26 26
 const BUTTON_ICON_OFF = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAbUlEQVRYR+2WOQ4AIAgE5f+PVhobDZANBZAsraAwXMoqFil+f9GBj8BW8dIiKt45at/XgShStHgvmfdekwAdIIEyAmh1Z/U5ikmABPoRsLZWtt+5DUlgHgGr6qM1Pf9XnO131L7fJEQjyOqXEzjP1YAhNmUTrgAAAABJRU5ErkJggg==';
@@ -47,8 +47,6 @@ export class FullscreenButton
47 47
     /** The HTML element of the button */
48 48
     private readonly _button: HTMLButtonElement;
49 49
 
50
-    /** Bound event handler */
51
-    private readonly _boundEventHandler: EventListener;
52 50
 
53 51
 
54 52
 
@@ -60,7 +58,7 @@ export class FullscreenButton
60 58
     {
61 59
         this._viewport = viewport;
62 60
         this._button = this._createButton();
63
-        this._boundEventHandler = this._handleFullscreenEvent.bind(this);
61
+        this._handleFullscreenEvent = this._handleFullscreenEvent.bind(this);
64 62
     }
65 63
 
66 64
     /**
@@ -72,7 +70,7 @@ export class FullscreenButton
72 70
     {
73 71
         parent.appendChild(this._button);
74 72
         this._button.hidden = !isVisible;
75
-        this._viewport.addEventListener('fullscreenchange', this._boundEventHandler);
73
+        this._viewport.addEventListener('fullscreenchange', this._handleFullscreenEvent);
76 74
     }
77 75
 
78 76
     /**
@@ -80,7 +78,7 @@ export class FullscreenButton
80 78
      */
81 79
     release(): void
82 80
     {
83
-        this._viewport.removeEventListener('fullscreenchange', this._boundEventHandler);
81
+        this._viewport.removeEventListener('fullscreenchange', this._handleFullscreenEvent);
84 82
         this._button.remove();
85 83
     }
86 84
 
@@ -145,7 +143,7 @@ export class FullscreenButton
145 143
     /**
146 144
      * Handle a fullscreenchange event
147 145
      */
148
-    private _handleFullscreenEvent(event: Event): void
146
+    private _handleFullscreenEvent(event: ViewportEvent): void
149 147
     {
150 148
         const img = this._viewport.fullscreen ? BUTTON_ICON_ON : BUTTON_ICON_OFF;
151 149
         this._button.style.backgroundImage = 'url(' + img + ')';

+ 3
- 2
src/ui/gizmos.ts 파일 보기

@@ -85,8 +85,9 @@ export class Gizmos
85 85
 
86 86
         // render the gizmos of each tracker
87 87
         for(let i = 0; i < trackers.length; i++) {
88
-            if(trackers[i].type == 'image-tracker') {
89
-                const output = trackers[i]._output as ImageTrackerOutput;
88
+            const tracker = trackers[i];
89
+            if(tracker.is('image-tracker')) {
90
+                const output = tracker._output;
90 91
                 this._imageTrackerGizmos.render(viewport, output);
91 92
             }
92 93
         }

+ 22
- 11
src/utils/ar-events.ts 파일 보기

@@ -22,15 +22,11 @@
22 22
 
23 23
 /**
24 24
  * AR Event Type
25
+ * @internal
25 26
  */
26 27
 type AREventType = string;
27 28
 
28 29
 /**
29
- * AR Event Listener (callback)
30
- */
31
-export type AREventListener = EventListener;
32
-
33
-/**
34 30
  * AR Event
35 31
  */
36 32
 export class AREvent<T extends AREventType> extends Event
@@ -54,9 +50,24 @@ export class AREvent<T extends AREventType> extends Event
54 50
 }
55 51
 
56 52
 /**
53
+ * Extract the AREventType from an AREvent
54
+ * @internal
55
+ */
56
+type AREventTypeOf<T> = T extends AREvent<infer U> ? U : never;
57
+
58
+/**
59
+ * AR Event Listener (a callback)
60
+ * @internal
61
+ */
62
+interface AREventListener<T>
63
+{
64
+    (evt: T extends AREvent<infer U> ? T : never): void;
65
+}
66
+
67
+/**
57 68
  * AR Event Target
58 69
  */
59
-export class AREventTarget<T extends AREventType> implements EventTarget
70
+export class AREventTarget<T>
60 71
 {
61 72
     /** event target delegate */
62 73
     private readonly _delegate: EventTarget;
@@ -76,9 +87,9 @@ export class AREventTarget<T extends AREventType> implements EventTarget
76 87
      * @param type event type
77 88
      * @param callback
78 89
      */
79
-    addEventListener(type: T, callback: AREventListener): void
90
+    addEventListener(type: AREventTypeOf<T>, callback: AREventListener<T>): void
80 91
     {
81
-        this._delegate.addEventListener(type, callback);
92
+        this._delegate.addEventListener(type, callback as EventListener);
82 93
     }
83 94
 
84 95
     /**
@@ -86,9 +97,9 @@ export class AREventTarget<T extends AREventType> implements EventTarget
86 97
      * @param type event type
87 98
      * @param callback
88 99
      */
89
-    removeEventListener(type: T, callback: AREventListener): void
100
+    removeEventListener(type: AREventTypeOf<T>, callback: AREventListener<T>): void
90 101
     {
91
-        this._delegate.removeEventListener(type, callback);
102
+        this._delegate.removeEventListener(type, callback as EventListener);
92 103
     }
93 104
 
94 105
     /**
@@ -97,7 +108,7 @@ export class AREventTarget<T extends AREventType> implements EventTarget
97 108
      * @returns same value as a standard event target
98 109
      * @internal
99 110
      */
100
-    dispatchEvent(event: AREvent<T>): boolean
111
+    dispatchEvent(event: T extends AREvent<infer U> ? T : never): boolean
101 112
     {
102 113
         return this._delegate.dispatchEvent(event);
103 114
     }

+ 1
- 1
tsconfig.json 파일 보기

@@ -3,7 +3,7 @@
3 3
         "target": "es2020",
4 4
         "module": "es6",
5 5
         "lib": ["dom", "es2020"],
6
-        "outDir": "./dist/",
6
+        "outDir": "./build",
7 7
         "sourceMap": true,
8 8
         "allowJs": true,
9 9
         "strict": true,

Loading…
취소
저장