@srsergio/taptapp-ar 1.0.25 → 1.0.27
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/compiler/simple-ar.d.ts +39 -22
- package/dist/compiler/simple-ar.js +44 -21
- package/package.json +1 -1
- package/src/compiler/simple-ar.js +48 -23
|
@@ -15,32 +15,49 @@
|
|
|
15
15
|
* await ar.start();
|
|
16
16
|
*/
|
|
17
17
|
export class SimpleAR {
|
|
18
|
+
/**
|
|
19
|
+
* @param {Object} options
|
|
20
|
+
* @param {HTMLElement} options.container
|
|
21
|
+
* @param {string|string[]} options.targetSrc
|
|
22
|
+
* @param {HTMLElement} options.overlay
|
|
23
|
+
* @param {number} [options.scale=1.0]
|
|
24
|
+
* @param {((data: {targetIndex: number}) => void | Promise<void>) | null} [options.onFound]
|
|
25
|
+
* @param {((data: {targetIndex: number}) => void | Promise<void>) | null} [options.onLost]
|
|
26
|
+
* @param {((data: {targetIndex: number, worldMatrix: number[]}) => void) | null} [options.onUpdate]
|
|
27
|
+
* @param {Object} [options.cameraConfig]
|
|
28
|
+
*/
|
|
18
29
|
constructor({ container, targetSrc, overlay, scale, onFound, onLost, onUpdate, cameraConfig, }: {
|
|
19
|
-
container:
|
|
20
|
-
targetSrc:
|
|
21
|
-
overlay:
|
|
30
|
+
container: HTMLElement;
|
|
31
|
+
targetSrc: string | string[];
|
|
32
|
+
overlay: HTMLElement;
|
|
22
33
|
scale?: number | undefined;
|
|
23
|
-
onFound?:
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
onFound?: ((data: {
|
|
35
|
+
targetIndex: number;
|
|
36
|
+
}) => void | Promise<void>) | null | undefined;
|
|
37
|
+
onLost?: ((data: {
|
|
38
|
+
targetIndex: number;
|
|
39
|
+
}) => void | Promise<void>) | null | undefined;
|
|
40
|
+
onUpdate?: ((data: {
|
|
41
|
+
targetIndex: number;
|
|
42
|
+
worldMatrix: number[];
|
|
43
|
+
}) => void) | null | undefined;
|
|
44
|
+
cameraConfig?: Object | undefined;
|
|
31
45
|
});
|
|
32
|
-
container:
|
|
33
|
-
targetSrc:
|
|
34
|
-
overlay:
|
|
46
|
+
container: HTMLElement;
|
|
47
|
+
targetSrc: string | string[];
|
|
48
|
+
overlay: HTMLElement;
|
|
35
49
|
scaleMultiplier: number;
|
|
36
|
-
onFound:
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
50
|
+
onFound: ((data: {
|
|
51
|
+
targetIndex: number;
|
|
52
|
+
}) => void | Promise<void>) | null;
|
|
53
|
+
onLost: ((data: {
|
|
54
|
+
targetIndex: number;
|
|
55
|
+
}) => void | Promise<void>) | null;
|
|
56
|
+
onUpdateCallback: ((data: {
|
|
57
|
+
targetIndex: number;
|
|
58
|
+
worldMatrix: number[];
|
|
59
|
+
}) => void) | null;
|
|
60
|
+
cameraConfig: Object;
|
|
44
61
|
video: HTMLVideoElement | null;
|
|
45
62
|
controller: Controller | null;
|
|
46
63
|
isTracking: boolean;
|
|
@@ -16,6 +16,17 @@ import { Controller } from "./controller.js";
|
|
|
16
16
|
* await ar.start();
|
|
17
17
|
*/
|
|
18
18
|
class SimpleAR {
|
|
19
|
+
/**
|
|
20
|
+
* @param {Object} options
|
|
21
|
+
* @param {HTMLElement} options.container
|
|
22
|
+
* @param {string|string[]} options.targetSrc
|
|
23
|
+
* @param {HTMLElement} options.overlay
|
|
24
|
+
* @param {number} [options.scale=1.0]
|
|
25
|
+
* @param {((data: {targetIndex: number}) => void | Promise<void>) | null} [options.onFound]
|
|
26
|
+
* @param {((data: {targetIndex: number}) => void | Promise<void>) | null} [options.onLost]
|
|
27
|
+
* @param {((data: {targetIndex: number, worldMatrix: number[]}) => void) | null} [options.onUpdate]
|
|
28
|
+
* @param {Object} [options.cameraConfig]
|
|
29
|
+
*/
|
|
19
30
|
constructor({ container, targetSrc, overlay, scale = 1.0, // Multiplicador de escala personalizado
|
|
20
31
|
onFound = null, onLost = null, onUpdate = null, cameraConfig = { facingMode: 'environment', width: 1280, height: 720 }, }) {
|
|
21
32
|
this.container = container;
|
|
@@ -45,6 +56,7 @@ class SimpleAR {
|
|
|
45
56
|
const targets = Array.isArray(this.targetSrc) ? this.targetSrc : [this.targetSrc];
|
|
46
57
|
const result = await this.controller.addImageTargets(targets);
|
|
47
58
|
this.markerDimensions = result.dimensions; // [ [w1, h1], [w2, h2], ... ]
|
|
59
|
+
console.log("Targets loaded. Dimensions:", this.markerDimensions);
|
|
48
60
|
this.controller.processVideo(this.video);
|
|
49
61
|
return this;
|
|
50
62
|
}
|
|
@@ -136,38 +148,49 @@ class SimpleAR {
|
|
|
136
148
|
const isPortrait = containerRect.height > containerRect.width;
|
|
137
149
|
const isVideoLandscape = videoW > videoH;
|
|
138
150
|
const needsRotation = isPortrait && isVideoLandscape;
|
|
139
|
-
//
|
|
140
|
-
const
|
|
141
|
-
|
|
151
|
+
// Current display dimensions of the video (accounting for rotation)
|
|
152
|
+
const vW = needsRotation ? videoH : videoW;
|
|
153
|
+
const vH = needsRotation ? videoW : videoH;
|
|
154
|
+
// Robust "object-fit: cover" scale calculation
|
|
155
|
+
const perspectiveScale = Math.max(containerRect.width / vW, containerRect.height / vH);
|
|
156
|
+
const displayW = vW * perspectiveScale;
|
|
157
|
+
const displayH = vH * perspectiveScale;
|
|
158
|
+
const offsetX = (containerRect.width - displayW) / 2;
|
|
159
|
+
const offsetY = (containerRect.height - displayH) / 2;
|
|
160
|
+
// The tracker uses focal length based on height dimension in tracker space
|
|
161
|
+
const f = (videoH / 2) / Math.tan((45.0 * Math.PI / 180) / 2);
|
|
162
|
+
// Center of the marker in camera space (marker coordinates origin at top-left)
|
|
142
163
|
const tx = mVT[0][0] * (markerW / 2) + mVT[0][1] * (markerH / 2) + mVT[0][3];
|
|
143
164
|
const ty = mVT[1][0] * (markerW / 2) + mVT[1][1] * (markerH / 2) + mVT[1][3];
|
|
144
165
|
const tz = mVT[2][0] * (markerW / 2) + mVT[2][1] * (markerH / 2) + mVT[2][3];
|
|
145
|
-
let screenX, screenY, rotation
|
|
166
|
+
let screenX, screenY, rotation;
|
|
146
167
|
if (needsRotation) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const offsetX = (containerRect.width - displayW) / 2;
|
|
152
|
-
// Mapping: Buffer +X (Right) -> Screen +Y (Down), Buffer +Y (Down) -> Screen -X (Left)
|
|
153
|
-
screenX = offsetX + (displayW / 2 - (ty * f / tz) * scale);
|
|
154
|
-
screenY = (containerRect.height / 2 + (tx * f / tz) * scale);
|
|
168
|
+
const bufferOffsetX = (tx * f / tz);
|
|
169
|
+
const bufferOffsetY = (ty * f / tz);
|
|
170
|
+
screenX = offsetX + (displayW / 2) - (bufferOffsetY * perspectiveScale);
|
|
171
|
+
screenY = offsetY + (displayH / 2) + (bufferOffsetX * perspectiveScale);
|
|
155
172
|
rotation = Math.atan2(mVT[1][0], mVT[0][0]) - Math.PI / 2;
|
|
156
|
-
perspectiveScale = scale;
|
|
157
173
|
}
|
|
158
174
|
else {
|
|
159
|
-
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
screenX = (containerRect.width / 2 + (tx * f / tz) * scale);
|
|
164
|
-
screenY = offsetY + (displayH / 2 + (ty * f / tz) * scale);
|
|
175
|
+
const bufferOffsetX = (tx * f / tz);
|
|
176
|
+
const bufferOffsetY = (ty * f / tz);
|
|
177
|
+
screenX = offsetX + (displayW / 2) + (bufferOffsetX * perspectiveScale);
|
|
178
|
+
screenY = offsetY + (displayH / 2) + (bufferOffsetY * perspectiveScale);
|
|
165
179
|
rotation = Math.atan2(mVT[1][0], mVT[0][0]);
|
|
166
|
-
perspectiveScale = scale;
|
|
167
180
|
}
|
|
168
|
-
// Final Scale
|
|
169
181
|
const matrixScale = Math.sqrt(mVT[0][0] ** 2 + mVT[1][0] ** 2);
|
|
170
182
|
const finalScale = (f / tz) * perspectiveScale * matrixScale * this.scaleMultiplier;
|
|
183
|
+
// DEBUG LOGS
|
|
184
|
+
if (window.AR_DEBUG) {
|
|
185
|
+
console.log('--- AR POSITION DEBUG ---');
|
|
186
|
+
console.log('Container:', containerRect.width, 'x', containerRect.height);
|
|
187
|
+
console.log('Video:', videoW, 'x', videoH, 'needsRotation:', needsRotation);
|
|
188
|
+
console.log('PerspectiveScale (Cover):', perspectiveScale);
|
|
189
|
+
console.log('Display:', displayW, 'x', displayH, 'Offsets:', offsetX, offsetY);
|
|
190
|
+
console.log('Projection (tx, ty, tz):', tx.toFixed(2), ty.toFixed(2), tz.toFixed(2));
|
|
191
|
+
console.log('Screen Coords:', screenX.toFixed(2), screenY.toFixed(2));
|
|
192
|
+
console.log('Final Scale:', finalScale.toFixed(4), '(MatrixScale:', matrixScale.toFixed(4), ')');
|
|
193
|
+
}
|
|
171
194
|
// Apply
|
|
172
195
|
this.overlay.style.width = `${markerW}px`;
|
|
173
196
|
this.overlay.style.height = 'auto';
|
package/package.json
CHANGED
|
@@ -17,6 +17,17 @@ import { Controller } from "./controller.js";
|
|
|
17
17
|
* await ar.start();
|
|
18
18
|
*/
|
|
19
19
|
class SimpleAR {
|
|
20
|
+
/**
|
|
21
|
+
* @param {Object} options
|
|
22
|
+
* @param {HTMLElement} options.container
|
|
23
|
+
* @param {string|string[]} options.targetSrc
|
|
24
|
+
* @param {HTMLElement} options.overlay
|
|
25
|
+
* @param {number} [options.scale=1.0]
|
|
26
|
+
* @param {((data: {targetIndex: number}) => void | Promise<void>) | null} [options.onFound]
|
|
27
|
+
* @param {((data: {targetIndex: number}) => void | Promise<void>) | null} [options.onLost]
|
|
28
|
+
* @param {((data: {targetIndex: number, worldMatrix: number[]}) => void) | null} [options.onUpdate]
|
|
29
|
+
* @param {Object} [options.cameraConfig]
|
|
30
|
+
*/
|
|
20
31
|
constructor({
|
|
21
32
|
container,
|
|
22
33
|
targetSrc,
|
|
@@ -59,6 +70,7 @@ class SimpleAR {
|
|
|
59
70
|
const targets = Array.isArray(this.targetSrc) ? this.targetSrc : [this.targetSrc];
|
|
60
71
|
const result = await this.controller.addImageTargets(targets);
|
|
61
72
|
this.markerDimensions = result.dimensions; // [ [w1, h1], [w2, h2], ... ]
|
|
73
|
+
console.log("Targets loaded. Dimensions:", this.markerDimensions);
|
|
62
74
|
|
|
63
75
|
this.controller.processVideo(this.video);
|
|
64
76
|
|
|
@@ -163,46 +175,59 @@ class SimpleAR {
|
|
|
163
175
|
const isVideoLandscape = videoW > videoH;
|
|
164
176
|
const needsRotation = isPortrait && isVideoLandscape;
|
|
165
177
|
|
|
166
|
-
//
|
|
167
|
-
const
|
|
178
|
+
// Current display dimensions of the video (accounting for rotation)
|
|
179
|
+
const vW = needsRotation ? videoH : videoW;
|
|
180
|
+
const vH = needsRotation ? videoW : videoH;
|
|
181
|
+
|
|
182
|
+
// Robust "object-fit: cover" scale calculation
|
|
183
|
+
const perspectiveScale = Math.max(containerRect.width / vW, containerRect.height / vH);
|
|
184
|
+
|
|
185
|
+
const displayW = vW * perspectiveScale;
|
|
186
|
+
const displayH = vH * perspectiveScale;
|
|
187
|
+
const offsetX = (containerRect.width - displayW) / 2;
|
|
188
|
+
const offsetY = (containerRect.height - displayH) / 2;
|
|
189
|
+
|
|
190
|
+
// The tracker uses focal length based on height dimension in tracker space
|
|
191
|
+
const f = (videoH / 2) / Math.tan((45.0 * Math.PI / 180) / 2);
|
|
168
192
|
|
|
169
|
-
//
|
|
193
|
+
// Center of the marker in camera space (marker coordinates origin at top-left)
|
|
170
194
|
const tx = mVT[0][0] * (markerW / 2) + mVT[0][1] * (markerH / 2) + mVT[0][3];
|
|
171
195
|
const ty = mVT[1][0] * (markerW / 2) + mVT[1][1] * (markerH / 2) + mVT[1][3];
|
|
172
196
|
const tz = mVT[2][0] * (markerW / 2) + mVT[2][1] * (markerH / 2) + mVT[2][3];
|
|
173
197
|
|
|
174
|
-
let screenX, screenY, rotation
|
|
198
|
+
let screenX, screenY, rotation;
|
|
175
199
|
|
|
176
200
|
if (needsRotation) {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const scale = containerRect.height / videoW;
|
|
180
|
-
const displayW = videoH * scale;
|
|
181
|
-
const offsetX = (containerRect.width - displayW) / 2;
|
|
182
|
-
|
|
183
|
-
// Mapping: Buffer +X (Right) -> Screen +Y (Down), Buffer +Y (Down) -> Screen -X (Left)
|
|
184
|
-
screenX = offsetX + (displayW / 2 - (ty * f / tz) * scale);
|
|
185
|
-
screenY = (containerRect.height / 2 + (tx * f / tz) * scale);
|
|
201
|
+
const bufferOffsetX = (tx * f / tz);
|
|
202
|
+
const bufferOffsetY = (ty * f / tz);
|
|
186
203
|
|
|
204
|
+
screenX = offsetX + (displayW / 2) - (bufferOffsetY * perspectiveScale);
|
|
205
|
+
screenY = offsetY + (displayH / 2) + (bufferOffsetX * perspectiveScale);
|
|
187
206
|
rotation = Math.atan2(mVT[1][0], mVT[0][0]) - Math.PI / 2;
|
|
188
|
-
perspectiveScale = scale;
|
|
189
207
|
} else {
|
|
190
|
-
|
|
191
|
-
const
|
|
192
|
-
const displayH = videoH * scale;
|
|
193
|
-
const offsetY = (containerRect.height - displayH) / 2;
|
|
194
|
-
|
|
195
|
-
screenX = (containerRect.width / 2 + (tx * f / tz) * scale);
|
|
196
|
-
screenY = offsetY + (displayH / 2 + (ty * f / tz) * scale);
|
|
208
|
+
const bufferOffsetX = (tx * f / tz);
|
|
209
|
+
const bufferOffsetY = (ty * f / tz);
|
|
197
210
|
|
|
211
|
+
screenX = offsetX + (displayW / 2) + (bufferOffsetX * perspectiveScale);
|
|
212
|
+
screenY = offsetY + (displayH / 2) + (bufferOffsetY * perspectiveScale);
|
|
198
213
|
rotation = Math.atan2(mVT[1][0], mVT[0][0]);
|
|
199
|
-
perspectiveScale = scale;
|
|
200
214
|
}
|
|
201
215
|
|
|
202
|
-
// Final Scale
|
|
203
216
|
const matrixScale = Math.sqrt(mVT[0][0] ** 2 + mVT[1][0] ** 2);
|
|
204
217
|
const finalScale = (f / tz) * perspectiveScale * matrixScale * this.scaleMultiplier;
|
|
205
218
|
|
|
219
|
+
// DEBUG LOGS
|
|
220
|
+
if (window.AR_DEBUG) {
|
|
221
|
+
console.log('--- AR POSITION DEBUG ---');
|
|
222
|
+
console.log('Container:', containerRect.width, 'x', containerRect.height);
|
|
223
|
+
console.log('Video:', videoW, 'x', videoH, 'needsRotation:', needsRotation);
|
|
224
|
+
console.log('PerspectiveScale (Cover):', perspectiveScale);
|
|
225
|
+
console.log('Display:', displayW, 'x', displayH, 'Offsets:', offsetX, offsetY);
|
|
226
|
+
console.log('Projection (tx, ty, tz):', tx.toFixed(2), ty.toFixed(2), tz.toFixed(2));
|
|
227
|
+
console.log('Screen Coords:', screenX.toFixed(2), screenY.toFixed(2));
|
|
228
|
+
console.log('Final Scale:', finalScale.toFixed(4), '(MatrixScale:', matrixScale.toFixed(4), ')');
|
|
229
|
+
}
|
|
230
|
+
|
|
206
231
|
// Apply
|
|
207
232
|
this.overlay.style.width = `${markerW}px`;
|
|
208
233
|
this.overlay.style.height = 'auto';
|