@virtualdisplay.io/client 4.0.0-alpha.2 → 4.0.0-alpha.21
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/CHANGELOG.md +150 -0
- package/README.md +85 -158
- package/dist/browser-DfB_An57.cjs +8 -0
- package/dist/browser-ey6Iih3j.js +1540 -0
- package/dist/index.d.ts +1158 -1
- package/dist/virtualdisplay.client.cjs.js +493 -1
- package/dist/virtualdisplay.client.es.js +3570 -794
- package/dist/virtualdisplay.client.umd.js +500 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,155 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 4.0.0-alpha.21
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
Add `activateAr()` method to `VirtualdisplayClient`. Triggers the AR flow directly, useful when the built-in AR button is hidden with `viewerSettings.ar = false` and a custom control should start AR instead.
|
|
8
|
+
|
|
9
|
+
Add `client.onSyncChange(callback)`: subscribe to whether the viewer is currently live-syncing its configuration with another device in a hand-off (e.g. a desktop and the phone it was scanned to). The callback receives a boolean and fires again each time the connection state changes.
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
Change the desktop AR button's QR code to open the model in AR on the phone with the shopper's current configuration, instead of a fresh default viewer. The QR dialog now opens immediately and shows the code as soon as it is ready.
|
|
14
|
+
|
|
15
|
+
## 4.0.0-alpha.20
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
Internal refactoring.
|
|
20
|
+
|
|
21
|
+
## 4.0.0-alpha.19
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
Fix the AR and fullscreen buttons being hidden behind the configurator open button when the sidebar layout collapses on narrow embeds.
|
|
26
|
+
|
|
27
|
+
## 4.0.0-alpha.18
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
Internal improvements.
|
|
32
|
+
|
|
33
|
+
## 4.0.0-alpha.17
|
|
34
|
+
|
|
35
|
+
### Minor Changes
|
|
36
|
+
|
|
37
|
+
Add `client.sessionId`: the viewer's tracking session id, available once the viewer has loaded (and `undefined` before). Use it to correlate your own page events, such as a form conversion, with the viewer session the visitor was using.
|
|
38
|
+
|
|
39
|
+
## 4.0.0-alpha.16
|
|
40
|
+
|
|
41
|
+
### Patch Changes
|
|
42
|
+
|
|
43
|
+
Internal: the client now assembles over a shared `@virtualdisplay.io/client-core` engine (transport, base facades, configurator UI). No public API change.
|
|
44
|
+
|
|
45
|
+
## 4.0.0-alpha.15
|
|
46
|
+
|
|
47
|
+
### Patch Changes
|
|
48
|
+
|
|
49
|
+
`snapshot.take()` now fails with `SNAPSHOT_FAILED` if the viewer does not return the capture within 30 seconds, instead of leaving `photo.onError()` waiting forever when the iframe is unresponsive. Also removed unused internal `VirtualdisplayError` factory helpers (`noMapping`, `attributeNotFound`, `snapshotFailed`); the error codes and public constructor are unchanged.
|
|
50
|
+
|
|
51
|
+
## 4.0.0-alpha.14
|
|
52
|
+
|
|
53
|
+
### Major Changes
|
|
54
|
+
|
|
55
|
+
Remove the `cache` option from `ClientOptions`. It was a test-only override and is gone, so remove it from your options if you passed it.
|
|
56
|
+
|
|
57
|
+
## 4.0.0-alpha.13
|
|
58
|
+
|
|
59
|
+
### Minor Changes
|
|
60
|
+
|
|
61
|
+
Add `client.configuration` for configurator commerce: the buyer's selection resolves to a reference and price, read via `client.configuration.current`, `.onChange`, or the bubbling `vd:configuration-change` event. Register a handler with `.onSubmit(cb, { defaultLabel })` to switch on the call-to-action, which renders the price and a customer-labelled button under the controls.
|
|
62
|
+
|
|
63
|
+
Show the submit CTA for a configurator without prices. When no pricing document is present, a registered `onSubmit` handler (with a label) is enough to offer the button, and submitting hands over the buyer's current selection. A model with only attributes, or none at all, can now be submitted. With prices, the CTA stays gated on an `available` price.
|
|
64
|
+
|
|
65
|
+
Add `client.focus` to isolate and frame a single component of a model. `client.focus.set('Seat')` flies the camera to that component and dims the rest; `client.focus.clear()` returns to the overview. Read the current component with `client.focus.current`, react to changes with `client.focus.onChange((state) => ...)`, or listen for the bubbling `vd:focus-change` event (`VD_EVENTS.FOCUS_CHANGE`) on the container. Useful for guiding a buyer through a configurable product part by part.
|
|
66
|
+
|
|
67
|
+
### Patch Changes
|
|
68
|
+
|
|
69
|
+
Remove the unused `AttributeRegistry.defaults()` method and mark
|
|
70
|
+
`MutationFailedEvent` fields as `readonly`, matching the other public event
|
|
71
|
+
types. Internal cleanup with no API change.
|
|
72
|
+
|
|
73
|
+
## 4.0.0-alpha.12
|
|
74
|
+
|
|
75
|
+
### Minor Changes
|
|
76
|
+
|
|
77
|
+
Add `configuratorLayout` to `ViewerSettings`: choose where the attribute selector sits — `'inframe-bottom-left'` (default) or `'sidebar-right'` (a docked, scrollable right-hand panel) — or `'hidden'` to drop it (`client.select()` and `client.onChange()` keep working). Configure it per model in the portal, or override it via `viewerSettings`. This replaces the `attributeControls` field; swap `attributeControls: false` for `configuratorLayout: 'hidden'`.
|
|
78
|
+
|
|
79
|
+
### Patch Changes
|
|
80
|
+
|
|
81
|
+
Internal build-config fix. Align `vite.config.ts` with vite 7 typings: rename `rolldownOptions` to `rollupOptions` and drop the `oxc` minifier (vite 7 only accepts `terser` and `esbuild` and was silently falling back to esbuild). No change to the published bundle.
|
|
82
|
+
|
|
83
|
+
`VirtualdisplayClient.destroy()` now fails any pending `snapshot.take()` captures with `SNAPSHOT_FAILED` and clears registered `onMutationFailed` callbacks. Previously, callers awaiting `photo.onError()` after a destroy would wait forever and listeners outlived the client they were attached to.
|
|
84
|
+
|
|
85
|
+
## 4.0.0-alpha.11
|
|
86
|
+
|
|
87
|
+
### Patch Changes
|
|
88
|
+
|
|
89
|
+
Hide the fullscreen button on iPhone Safari, where the browser has no Fullscreen API for non-video elements. The button continues to work on desktop, iPad, and Android Chrome.
|
|
90
|
+
|
|
91
|
+
## 4.0.0-alpha.10
|
|
92
|
+
|
|
93
|
+
### Patch Changes
|
|
94
|
+
|
|
95
|
+
Fix AR button on mobile to launch native AR (Quick Look on iOS, Scene Viewer on Android) instead of the QR modal. Fix fullscreen button on iPhone Safari.
|
|
96
|
+
|
|
97
|
+
## 4.0.0-alpha.9
|
|
98
|
+
|
|
99
|
+
### Patch Changes
|
|
100
|
+
|
|
101
|
+
Fix state mix-up when multiple `VirtualdisplayClient` instances are mounted on the same page. Each client now correctly receives only its own server replies, so loading state, mapping, and mutation results no longer cross between viewers.
|
|
102
|
+
|
|
103
|
+
## 4.0.0-alpha.8
|
|
104
|
+
|
|
105
|
+
### Minor Changes
|
|
106
|
+
|
|
107
|
+
Add `viewerSettings` option to `ClientOptions`. Pass a partial `ViewerSettings` to override fields like `ar`, `fullscreen`, `cameraControls`, `attributeControls`, or `annotations` without changing the model's metadata.
|
|
108
|
+
|
|
109
|
+
Add annotations API: `client.annotations.setEnabled(enabled)` toggles annotation markers, and `startPlacing()` / `stopPlacing()` / `onPlaced(callback)` enable click-to-place flows for custom annotation editors. New `AnnotationPosition` type is exported.
|
|
110
|
+
|
|
111
|
+
Add `attributeControls` field to `ViewerSettings`. Set to `false` to hide the built-in attribute selector while keeping `client.select()` and `client.onChange()` available.
|
|
112
|
+
|
|
113
|
+
Fix toolbar buttons appearing briefly before the loading indicator clears.
|
|
114
|
+
|
|
115
|
+
Fix annotation markers ignoring `annotations: false` when set via the `viewerSettings` override.
|
|
116
|
+
|
|
117
|
+
Fix loading indicator hanging when model metadata is unavailable.
|
|
118
|
+
|
|
119
|
+
Internal code quality improvements.
|
|
120
|
+
|
|
121
|
+
## 4.0.0-alpha.7
|
|
122
|
+
|
|
123
|
+
### Patch Changes
|
|
124
|
+
|
|
125
|
+
Restructure standard interface layout to use corner slots. Camera controls and screenshot button now share a single card when both are enabled.
|
|
126
|
+
|
|
127
|
+
## 4.0.0-alpha.6
|
|
128
|
+
|
|
129
|
+
### Patch Changes
|
|
130
|
+
|
|
131
|
+
Fix camera control buttons accumulating clicks correctly.
|
|
132
|
+
|
|
133
|
+
## 4.0.0-alpha.5
|
|
134
|
+
|
|
135
|
+
### Patch Changes
|
|
136
|
+
|
|
137
|
+
Internal code quality improvements.
|
|
138
|
+
|
|
139
|
+
Ship complete TypeScript type definitions for all exports.
|
|
140
|
+
|
|
141
|
+
## 4.0.0-alpha.4
|
|
142
|
+
|
|
143
|
+
### Minor Changes
|
|
144
|
+
|
|
145
|
+
Add `language` option to `ClientOptions`. Pass a BCP 47 language tag (e.g. `"nl"`, `"de"`) to override the viewer language at initialisation time. Useful when embedding the same model on multiple pages with different languages.
|
|
146
|
+
|
|
147
|
+
Add built-in standard interface: loading indicator, toolbar (screenshot, AR, fullscreen), camera controls, and attribute controls are now rendered automatically inside the viewer container. UI is driven by `viewerSettings` received from the server and requires no manual setup.
|
|
148
|
+
|
|
149
|
+
### Patch Changes
|
|
150
|
+
|
|
151
|
+
Fix build target: use ESNext in tsconfig to resolve rolldown bundling issues with ES2022 class fields.
|
|
152
|
+
|
|
3
153
|
## 4.0.0-alpha.2
|
|
4
154
|
|
|
5
155
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
TypeScript library for embedding interactive 3D product models in web
|
|
4
4
|
applications.
|
|
5
5
|
|
|
6
|
+
- Built-in viewer UI with loading indicator, product controls, and action bar
|
|
6
7
|
- Simple attribute-based API for product configurators
|
|
7
8
|
- Server-driven configuration, no client-side mapping needed
|
|
8
9
|
- Fire-and-forget messaging with automatic state synchronisation
|
|
@@ -60,43 +61,19 @@ The 3D server hosts the viewer in an iframe, keeping WebGL complexity isolated
|
|
|
60
61
|
from your application. The client library handles all communication via
|
|
61
62
|
postMessage.
|
|
62
63
|
|
|
63
|
-
|
|
64
|
-
graph LR
|
|
65
|
-
A[Your application] -->|API calls| B[VirtualdisplayClient]
|
|
66
|
-
B -->|postMessage| C[3D server iframe]
|
|
67
|
-
C -->|Events| B
|
|
68
|
-
B -->|State updates| A
|
|
69
|
-
```
|
|
64
|
+

|
|
70
65
|
|
|
71
|
-
On startup, the server
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
sequenceDiagram
|
|
77
|
-
participant UI as Your UI
|
|
78
|
-
participant Client as VirtualdisplayClient
|
|
79
|
-
participant Server as 3D server
|
|
80
|
-
|
|
81
|
-
UI ->> Client: new VirtualdisplayClient(options)
|
|
82
|
-
Client ->> Client: Create iframe
|
|
83
|
-
Note right of Client: Outgoing messages queued
|
|
84
|
-
Server ->> Client: READY
|
|
85
|
-
Note right of Client: Queue flushed
|
|
86
|
-
opt UI or camera options configured
|
|
87
|
-
Client ->> Server: CONFIG
|
|
88
|
-
end
|
|
89
|
-
Server ->> Client: MAPPING (attributes + values + defaults)
|
|
90
|
-
Client ->> Client: Store attribute definitions
|
|
91
|
-
Server ->> Client: MUTATION result (defaults, isInitial: true)
|
|
92
|
-
Client ->> UI: onReady + onChange callbacks fire
|
|
93
|
-
```
|
|
66
|
+
On startup, the server sends the client its configuration (viewer settings,
|
|
67
|
+
camera limits) and available product attributes. The loading indicator shows
|
|
68
|
+
progress while the model downloads.
|
|
69
|
+
|
|
70
|
+

|
|
94
71
|
|
|
95
72
|
1. Client creates iframe; outgoing messages are queued until the server is ready.
|
|
96
|
-
2. Server sends `
|
|
97
|
-
3.
|
|
98
|
-
4. Server sends `
|
|
99
|
-
5. `
|
|
73
|
+
2. Server sends `HANDSHAKE` when its message listener is active; client flushes queue.
|
|
74
|
+
3. Server sends progress updates while the model downloads. The client displays these in the loading indicator.
|
|
75
|
+
4. Server sends `CONFIG` with viewer settings and camera limits from model metadata.
|
|
76
|
+
5. Server sends `MAPPING` with attribute definitions, values, and defaults. `onReady` fires.
|
|
100
77
|
|
|
101
78
|
## Product configuration
|
|
102
79
|
|
|
@@ -104,23 +81,7 @@ Configure product options by selecting attribute values. The server defines
|
|
|
104
81
|
which attributes exist (e.g. "Color", "Size") and which values each has
|
|
105
82
|
(e.g. "red", "blue"). You select values; the 3D model updates automatically.
|
|
106
83
|
|
|
107
|
-
|
|
108
|
-
sequenceDiagram
|
|
109
|
-
participant UI as Your UI
|
|
110
|
-
participant Client as VirtualdisplayClient
|
|
111
|
-
participant Server as 3D server
|
|
112
|
-
|
|
113
|
-
UI ->> Client: client.select('Color', 'blue')
|
|
114
|
-
Client ->> Server: MUTATION
|
|
115
|
-
Note right of Client: Fire-and-forget
|
|
116
|
-
Server ->> Server: Apply 3D changes
|
|
117
|
-
Server ->> Client: MUTATION result
|
|
118
|
-
alt All succeeded
|
|
119
|
-
Client ->> UI: onChange callbacks fire
|
|
120
|
-
else Some failed
|
|
121
|
-
Client ->> UI: onMutationFailed callbacks fire
|
|
122
|
-
end
|
|
123
|
-
```
|
|
84
|
+

|
|
124
85
|
|
|
125
86
|
- `select()` returns immediately; the result arrives asynchronously.
|
|
126
87
|
- Each attribute in the result has its own `success` flag and optional `error`.
|
|
@@ -134,8 +95,8 @@ client.select('Color', 'blue');
|
|
|
134
95
|
client.select('Size', 'large');
|
|
135
96
|
```
|
|
136
97
|
|
|
137
|
-
Can be called
|
|
138
|
-
|
|
98
|
+
Can be called immediately after construction. Selections are buffered until the
|
|
99
|
+
server handshake completes.
|
|
139
100
|
|
|
140
101
|
### Tracking changes
|
|
141
102
|
|
|
@@ -192,22 +153,7 @@ client.onMutationFailed(({ attribute, value }) => {
|
|
|
192
153
|
Capture the current 3D view as an image. Useful for product shots, social
|
|
193
154
|
sharing, or saving configurations.
|
|
194
155
|
|
|
195
|
-
|
|
196
|
-
sequenceDiagram
|
|
197
|
-
participant UI as Your UI
|
|
198
|
-
participant Client as VirtualdisplayClient
|
|
199
|
-
participant Server as 3D server
|
|
200
|
-
|
|
201
|
-
UI ->> Client: client.snapshot.take('photo.png')
|
|
202
|
-
Client ->> Server: SNAPSHOT request
|
|
203
|
-
alt Success
|
|
204
|
-
Server ->> Client: SNAPSHOT data (base64)
|
|
205
|
-
Client ->> UI: onDeveloped callback fires
|
|
206
|
-
else Failure (e.g. no canvas)
|
|
207
|
-
Server ->> Client: SNAPSHOT error
|
|
208
|
-
Client ->> UI: onError callback fires
|
|
209
|
-
end
|
|
210
|
-
```
|
|
156
|
+

|
|
211
157
|
|
|
212
158
|
- Filename is validated client-side (extension, no path traversal).
|
|
213
159
|
- Server always responds, either with image data or an error reason.
|
|
@@ -236,21 +182,11 @@ Filename must end with `.png`. The server always returns PNG data.
|
|
|
236
182
|
|
|
237
183
|
## Camera
|
|
238
184
|
|
|
239
|
-
|
|
240
|
-
|
|
185
|
+
The standard interface includes built-in camera controls when they are
|
|
186
|
+
enabled in the Virtualdisplay portal. The camera can also be controlled
|
|
187
|
+
programmatically.
|
|
241
188
|
|
|
242
|
-
|
|
243
|
-
sequenceDiagram
|
|
244
|
-
participant UI as Your UI
|
|
245
|
-
participant Client as VirtualdisplayClient
|
|
246
|
-
participant Server as 3D server
|
|
247
|
-
|
|
248
|
-
UI ->> Client: client.camera.rotate(45).tilt(30).set()
|
|
249
|
-
Client ->> Server: CAMERA commands
|
|
250
|
-
Server ->> Client: CAMERA position
|
|
251
|
-
Client ->> UI: camera.onChange callbacks fire
|
|
252
|
-
Note right of Server: Position updates also fire on user<br/>interaction with the 3D viewport
|
|
253
|
-
```
|
|
189
|
+

|
|
254
190
|
|
|
255
191
|
- Commands accumulate via chaining; `.set()` sends them all at once.
|
|
256
192
|
- `.reset()` sends immediately without chaining.
|
|
@@ -263,7 +199,7 @@ sequenceDiagram
|
|
|
263
199
|
client.camera.rotate(45).set();
|
|
264
200
|
client.camera.rotate(90).tilt(45).zoom(150).set();
|
|
265
201
|
|
|
266
|
-
// Reset to
|
|
202
|
+
// Reset to the default position configured in the portal (sends immediately)
|
|
267
203
|
client.camera.reset();
|
|
268
204
|
```
|
|
269
205
|
|
|
@@ -283,49 +219,78 @@ console.log(client.cameraPosition.tilt);
|
|
|
283
219
|
console.log(client.cameraPosition.zoom);
|
|
284
220
|
```
|
|
285
221
|
|
|
286
|
-
##
|
|
222
|
+
## Annotations
|
|
287
223
|
|
|
288
|
-
|
|
289
|
-
|
|
224
|
+
Annotations are interactive markers placed on the 3D model. They are
|
|
225
|
+
configured and saved in the Virtualdisplay portal. The client library
|
|
226
|
+
exposes an API to toggle their visibility.
|
|
290
227
|
|
|
291
|
-
###
|
|
228
|
+
### Toggling annotations
|
|
292
229
|
|
|
293
230
|
```typescript
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
license: 'your-license',
|
|
297
|
-
model: 'product',
|
|
298
|
-
ui: {
|
|
299
|
-
arEnabled: false,
|
|
300
|
-
loadingIndicatorEnabled: false,
|
|
301
|
-
},
|
|
302
|
-
});
|
|
231
|
+
client.annotations.setEnabled(false); // Hide all markers
|
|
232
|
+
client.annotations.setEnabled(true); // Show them again
|
|
303
233
|
```
|
|
304
234
|
|
|
305
|
-
|
|
235
|
+
Visibility can also be controlled via `viewerSettings.annotations` (see below).
|
|
236
|
+
|
|
237
|
+
## Standard interface
|
|
238
|
+
|
|
239
|
+
The client renders a complete viewer UI automatically: loading indicator,
|
|
240
|
+
attribute controls, camera controls, and an action bar with AR, fullscreen,
|
|
241
|
+
and screenshot buttons. Each element is shown or hidden based on viewer
|
|
242
|
+
settings configured in the Virtualdisplay portal.
|
|
243
|
+
|
|
244
|
+
### Available settings
|
|
245
|
+
|
|
246
|
+
| Field | Type | Effect when `false` |
|
|
247
|
+
| ------------------- | --------- | ---------------------------------------------------------------------------------------------- |
|
|
248
|
+
| `ar` | `boolean` | Hides the AR button |
|
|
249
|
+
| `fullscreen` | `boolean` | Hides the fullscreen button |
|
|
250
|
+
| `screenshot` | `boolean` | Hides the screenshot button |
|
|
251
|
+
| `cameraControls` | `boolean` | Hides the camera control buttons |
|
|
252
|
+
| `annotations` | `boolean` | Hides all annotation markers |
|
|
253
|
+
| `language` | `string` | Sets the viewer UI language (BCP 47, e.g. `'nl'`, `'en'`, `'de'`) |
|
|
254
|
+
| `configuratorLayout`| `string` | Where the attribute controls sit, or whether they show: `'inframe-bottom-left'` (default), `'sidebar-right'` (a docked, scrollable right-hand panel), or `'hidden'` (no built-in selector, `client.select()` and `client.onChange()` keep working). |
|
|
255
|
+
|
|
256
|
+
### Overriding settings
|
|
257
|
+
|
|
258
|
+
The portal is the recommended place to change these settings: one source of
|
|
259
|
+
truth, and the viewer behaves the same wherever it is embedded.
|
|
260
|
+
|
|
261
|
+
We know there are situations where the portal alone cannot cover the case at
|
|
262
|
+
hand. For those, `ClientOptions.viewerSettings` accepts a partial override of
|
|
263
|
+
the same fields. Use it sparingly: every override is one more place where
|
|
264
|
+
the embedded viewer disagrees with the portal. Omitted fields fall back to
|
|
265
|
+
the metadata value.
|
|
266
|
+
|
|
267
|
+
Any override that differs from the metadata is logged with `console.warn`.
|
|
268
|
+
The warning is always emitted, so the deviation stays traceable when
|
|
269
|
+
something needs explaining.
|
|
306
270
|
|
|
307
271
|
```typescript
|
|
308
|
-
client
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
272
|
+
const client = new VirtualdisplayClient({
|
|
273
|
+
parent: '#product-container',
|
|
274
|
+
license: 'your-license-key',
|
|
275
|
+
model: 'sneaker',
|
|
276
|
+
viewerSettings: {
|
|
277
|
+
cameraControls: false,
|
|
278
|
+
},
|
|
279
|
+
});
|
|
316
280
|
```
|
|
317
281
|
|
|
318
282
|
## Lifecycle
|
|
319
283
|
|
|
320
284
|
### Ready state
|
|
321
285
|
|
|
322
|
-
Use `onReady` to know when the
|
|
323
|
-
|
|
324
|
-
|
|
286
|
+
Use `onReady` to know when the model and attribute definitions are available.
|
|
287
|
+
Not required before calling `select()` or `onChange()`, those are buffered
|
|
288
|
+
automatically.
|
|
325
289
|
|
|
326
290
|
```typescript
|
|
327
291
|
client.onReady(() => {
|
|
328
|
-
|
|
292
|
+
const values = client.getValues('Color');
|
|
293
|
+
console.log('Available colours:', values.map(v => v.value));
|
|
329
294
|
});
|
|
330
295
|
```
|
|
331
296
|
|
|
@@ -338,30 +303,15 @@ client.destroy();
|
|
|
338
303
|
## Constructor options
|
|
339
304
|
|
|
340
305
|
```typescript
|
|
306
|
+
import type { ViewerSettings } from '@virtualdisplay.io/client';
|
|
307
|
+
|
|
341
308
|
interface ClientOptions {
|
|
342
|
-
parent: string | HTMLElement;
|
|
343
|
-
license: string;
|
|
344
|
-
model: string;
|
|
345
|
-
debug?: boolean;
|
|
346
|
-
language?: string;
|
|
347
|
-
|
|
348
|
-
// UI elements (all visible by default)
|
|
349
|
-
ui?: {
|
|
350
|
-
arEnabled?: boolean;
|
|
351
|
-
fullscreenEnabled?: boolean;
|
|
352
|
-
loadingIndicatorEnabled?: boolean;
|
|
353
|
-
};
|
|
354
|
-
|
|
355
|
-
// Camera behaviour
|
|
356
|
-
camera?: {
|
|
357
|
-
initialRotate?: number; // Starting view angle (-180 to 180, 0 = front)
|
|
358
|
-
initialTilt?: number; // Starting elevation (0 = top view, 90 = side view)
|
|
359
|
-
initialZoom?: number; // Starting distance (100 = default, may need adjustment)
|
|
360
|
-
minZoom?: number; // Minimum zoom level constraint
|
|
361
|
-
maxZoom?: number; // Maximum zoom level constraint
|
|
362
|
-
minTilt?: number; // Minimum tilt angle constraint
|
|
363
|
-
maxTilt?: number; // Maximum tilt angle constraint
|
|
364
|
-
};
|
|
309
|
+
parent: string | HTMLElement; // Where to embed the 3D viewer
|
|
310
|
+
license: string; // License key from your Virtualdisplay account
|
|
311
|
+
model: string; // Which 3D model to load
|
|
312
|
+
debug?: boolean; // Shows console logs for troubleshooting
|
|
313
|
+
language?: string; // Viewer language: 'nl', 'en', or 'de'
|
|
314
|
+
viewerSettings?: Partial<ViewerSettings>; // Override fields from model metadata (see Standard interface)
|
|
365
315
|
}
|
|
366
316
|
```
|
|
367
317
|
|
|
@@ -370,37 +320,14 @@ interface ClientOptions {
|
|
|
370
320
|
The client throws `VirtualdisplayError` for known error conditions:
|
|
371
321
|
|
|
372
322
|
| Code | Meaning |
|
|
373
|
-
|
|
323
|
+
| --------------------- | ------------------------------------------------ |
|
|
324
|
+
| `NO_MAPPING` | Attribute data not yet available from the server |
|
|
374
325
|
| `ATTRIBUTE_NOT_FOUND` | Requested attribute doesn't exist in the mapping |
|
|
375
326
|
| `VALUE_NOT_FOUND` | Requested value doesn't exist for attribute |
|
|
376
327
|
| `PARENT_NOT_FOUND` | Parent element for iframe not found |
|
|
377
328
|
| `INVALID_PARAMETER` | Invalid parameter (e.g. snapshot filename) |
|
|
378
329
|
| `SNAPSHOT_FAILED` | Server could not capture the snapshot |
|
|
379
330
|
|
|
380
|
-
## Real-world example
|
|
381
|
-
|
|
382
|
-
```typescript
|
|
383
|
-
const client = new VirtualdisplayClient({
|
|
384
|
-
parent: '#product-viewer',
|
|
385
|
-
license: 'your-license',
|
|
386
|
-
model: 'dining-table',
|
|
387
|
-
});
|
|
388
|
-
|
|
389
|
-
// Wire up your product option buttons. Selections are buffered until ready.
|
|
390
|
-
document.querySelectorAll('.color-option').forEach((button) => {
|
|
391
|
-
button.addEventListener('click', () => {
|
|
392
|
-
client.select('topMaterial', button.dataset.value);
|
|
393
|
-
});
|
|
394
|
-
});
|
|
395
|
-
|
|
396
|
-
// Keep buttons in sync with 3D state
|
|
397
|
-
client.onChange('topMaterial', (selectedValue) => {
|
|
398
|
-
document.querySelectorAll('.color-option').forEach((btn) => {
|
|
399
|
-
btn.classList.toggle('active', btn.dataset.value === selectedValue.value);
|
|
400
|
-
});
|
|
401
|
-
});
|
|
402
|
-
```
|
|
403
|
-
|
|
404
331
|
## Troubleshooting
|
|
405
332
|
|
|
406
333
|
**Iframe not loading:**
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";function re(r,o){for(var i=0;i<o.length;i++){const e=o[i];if(typeof e!="string"&&!Array.isArray(e)){for(const t in e)if(t!=="default"&&!(t in r)){const n=Object.getOwnPropertyDescriptor(e,t);n&&Object.defineProperty(r,t,n.get?n:{enumerable:!0,get:()=>e[t]})}}}return Object.freeze(Object.defineProperty(r,Symbol.toStringTag,{value:"Module"}))}function oe(r){return r&&r.__esModule&&Object.prototype.hasOwnProperty.call(r,"default")?r.default:r}var z={},Q,Bt;function ie(){return Bt||(Bt=1,Q=function(){return typeof Promise=="function"&&Promise.prototype&&Promise.prototype.then}),Q}var $={},_={},At;function U(){if(At)return _;At=1;let r;const o=[0,26,44,70,100,134,172,196,242,292,346,404,466,532,581,655,733,815,901,991,1085,1156,1258,1364,1474,1588,1706,1828,1921,2051,2185,2323,2465,2611,2761,2876,3034,3196,3362,3532,3706];return _.getSymbolSize=function(e){if(!e)throw new Error('"version" cannot be null or undefined');if(e<1||e>40)throw new Error('"version" should be in range from 1 to 40');return e*4+17},_.getSymbolTotalCodewords=function(e){return o[e]},_.getBCHDigit=function(i){let e=0;for(;i!==0;)e++,i>>>=1;return e},_.setToSJISFunction=function(e){if(typeof e!="function")throw new Error('"toSJISFunc" is not a valid function.');r=e},_.isKanjiModeEnabled=function(){return typeof r<"u"},_.toSJIS=function(e){return r(e)},_}var W={},Rt;function yt(){return Rt||(Rt=1,(function(r){r.L={bit:1},r.M={bit:0},r.Q={bit:3},r.H={bit:2};function o(i){if(typeof i!="string")throw new Error("Param is not a string");switch(i.toLowerCase()){case"l":case"low":return r.L;case"m":case"medium":return r.M;case"q":case"quartile":return r.Q;case"h":case"high":return r.H;default:throw new Error("Unknown EC Level: "+i)}}r.isValid=function(e){return e&&typeof e.bit<"u"&&e.bit>=0&&e.bit<4},r.from=function(e,t){if(r.isValid(e))return e;try{return o(e)}catch{return t}}})(W)),W}var Z,Tt;function ue(){if(Tt)return Z;Tt=1;function r(){this.buffer=[],this.length=0}return r.prototype={get:function(o){const i=Math.floor(o/8);return(this.buffer[i]>>>7-o%8&1)===1},put:function(o,i){for(let e=0;e<i;e++)this.putBit((o>>>i-e-1&1)===1)},getLengthInBits:function(){return this.length},putBit:function(o){const i=Math.floor(this.length/8);this.buffer.length<=i&&this.buffer.push(0),o&&(this.buffer[i]|=128>>>this.length%8),this.length++}},Z=r,Z}var X,Pt;function se(){if(Pt)return X;Pt=1;function r(o){if(!o||o<1)throw new Error("BitMatrix size must be defined and greater than 0");this.size=o,this.data=new Uint8Array(o*o),this.reservedBit=new Uint8Array(o*o)}return r.prototype.set=function(o,i,e,t){const n=o*this.size+i;this.data[n]=e,t&&(this.reservedBit[n]=!0)},r.prototype.get=function(o,i){return this.data[o*this.size+i]},r.prototype.xor=function(o,i,e){this.data[o*this.size+i]^=e},r.prototype.isReserved=function(o,i){return this.reservedBit[o*this.size+i]},X=r,X}var x={},It;function ae(){return It||(It=1,(function(r){const o=U().getSymbolSize;r.getRowColCoords=function(e){if(e===1)return[];const t=Math.floor(e/7)+2,n=o(e),u=n===145?26:Math.ceil((n-13)/(2*t-2))*2,a=[n-7];for(let s=1;s<t-1;s++)a[s]=a[s-1]-u;return a.push(6),a.reverse()},r.getPositions=function(e){const t=[],n=r.getRowColCoords(e),u=n.length;for(let a=0;a<u;a++)for(let s=0;s<u;s++)a===0&&s===0||a===0&&s===u-1||a===u-1&&s===0||t.push([n[a],n[s]]);return t}})(x)),x}var tt={},Nt;function ce(){if(Nt)return tt;Nt=1;const r=U().getSymbolSize,o=7;return tt.getPositions=function(e){const t=r(e);return[[0,0],[t-o,0],[0,t-o]]},tt}var et={},Mt;function fe(){return Mt||(Mt=1,(function(r){r.Patterns={PATTERN000:0,PATTERN001:1,PATTERN010:2,PATTERN011:3,PATTERN100:4,PATTERN101:5,PATTERN110:6,PATTERN111:7};const o={N1:3,N2:3,N3:40,N4:10};r.isValid=function(t){return t!=null&&t!==""&&!isNaN(t)&&t>=0&&t<=7},r.from=function(t){return r.isValid(t)?parseInt(t,10):void 0},r.getPenaltyN1=function(t){const n=t.size;let u=0,a=0,s=0,c=null,d=null;for(let p=0;p<n;p++){a=s=0,c=d=null;for(let h=0;h<n;h++){let f=t.get(p,h);f===c?a++:(a>=5&&(u+=o.N1+(a-5)),c=f,a=1),f=t.get(h,p),f===d?s++:(s>=5&&(u+=o.N1+(s-5)),d=f,s=1)}a>=5&&(u+=o.N1+(a-5)),s>=5&&(u+=o.N1+(s-5))}return u},r.getPenaltyN2=function(t){const n=t.size;let u=0;for(let a=0;a<n-1;a++)for(let s=0;s<n-1;s++){const c=t.get(a,s)+t.get(a,s+1)+t.get(a+1,s)+t.get(a+1,s+1);(c===4||c===0)&&u++}return u*o.N2},r.getPenaltyN3=function(t){const n=t.size;let u=0,a=0,s=0;for(let c=0;c<n;c++){a=s=0;for(let d=0;d<n;d++)a=a<<1&2047|t.get(c,d),d>=10&&(a===1488||a===93)&&u++,s=s<<1&2047|t.get(d,c),d>=10&&(s===1488||s===93)&&u++}return u*o.N3},r.getPenaltyN4=function(t){let n=0;const u=t.data.length;for(let s=0;s<u;s++)n+=t.data[s];return Math.abs(Math.ceil(n*100/u/5)-10)*o.N4};function i(e,t,n){switch(e){case r.Patterns.PATTERN000:return(t+n)%2===0;case r.Patterns.PATTERN001:return t%2===0;case r.Patterns.PATTERN010:return n%3===0;case r.Patterns.PATTERN011:return(t+n)%3===0;case r.Patterns.PATTERN100:return(Math.floor(t/2)+Math.floor(n/3))%2===0;case r.Patterns.PATTERN101:return t*n%2+t*n%3===0;case r.Patterns.PATTERN110:return(t*n%2+t*n%3)%2===0;case r.Patterns.PATTERN111:return(t*n%3+(t+n)%2)%2===0;default:throw new Error("bad maskPattern:"+e)}}r.applyMask=function(t,n){const u=n.size;for(let a=0;a<u;a++)for(let s=0;s<u;s++)n.isReserved(s,a)||n.xor(s,a,i(t,s,a))},r.getBestMask=function(t,n){const u=Object.keys(r.Patterns).length;let a=0,s=1/0;for(let c=0;c<u;c++){n(c),r.applyMask(c,t);const d=r.getPenaltyN1(t)+r.getPenaltyN2(t)+r.getPenaltyN3(t)+r.getPenaltyN4(t);r.applyMask(c,t),d<s&&(s=d,a=c)}return a}})(et)),et}var O={},bt;function $t(){if(bt)return O;bt=1;const r=yt(),o=[1,1,1,1,1,1,1,1,1,1,2,2,1,2,2,4,1,2,4,4,2,4,4,4,2,4,6,5,2,4,6,6,2,5,8,8,4,5,8,8,4,5,8,11,4,8,10,11,4,9,12,16,4,9,16,16,6,10,12,18,6,10,17,16,6,11,16,19,6,13,18,21,7,14,21,25,8,16,20,25,8,17,23,25,9,17,23,34,9,18,25,30,10,20,27,32,12,21,29,35,12,23,34,37,12,25,34,40,13,26,35,42,14,28,38,45,15,29,40,48,16,31,43,51,17,33,45,54,18,35,48,57,19,37,51,60,19,38,53,63,20,40,56,66,21,43,59,70,22,45,62,74,24,47,65,77,25,49,68,81],i=[7,10,13,17,10,16,22,28,15,26,36,44,20,36,52,64,26,48,72,88,36,64,96,112,40,72,108,130,48,88,132,156,60,110,160,192,72,130,192,224,80,150,224,264,96,176,260,308,104,198,288,352,120,216,320,384,132,240,360,432,144,280,408,480,168,308,448,532,180,338,504,588,196,364,546,650,224,416,600,700,224,442,644,750,252,476,690,816,270,504,750,900,300,560,810,960,312,588,870,1050,336,644,952,1110,360,700,1020,1200,390,728,1050,1260,420,784,1140,1350,450,812,1200,1440,480,868,1290,1530,510,924,1350,1620,540,980,1440,1710,570,1036,1530,1800,570,1064,1590,1890,600,1120,1680,1980,630,1204,1770,2100,660,1260,1860,2220,720,1316,1950,2310,750,1372,2040,2430];return O.getBlocksCount=function(t,n){switch(n){case r.L:return o[(t-1)*4+0];case r.M:return o[(t-1)*4+1];case r.Q:return o[(t-1)*4+2];case r.H:return o[(t-1)*4+3];default:return}},O.getTotalCodewordsCount=function(t,n){switch(n){case r.L:return i[(t-1)*4+0];case r.M:return i[(t-1)*4+1];case r.Q:return i[(t-1)*4+2];case r.H:return i[(t-1)*4+3];default:return}},O}var nt={},K={},St;function le(){if(St)return K;St=1;const r=new Uint8Array(512),o=new Uint8Array(256);return(function(){let e=1;for(let t=0;t<255;t++)r[t]=e,o[e]=t,e<<=1,e&256&&(e^=285);for(let t=255;t<512;t++)r[t]=r[t-255]})(),K.log=function(e){if(e<1)throw new Error("log("+e+")");return o[e]},K.exp=function(e){return r[e]},K.mul=function(e,t){return e===0||t===0?0:r[o[e]+o[t]]},K}var Lt;function de(){return Lt||(Lt=1,(function(r){const o=le();r.mul=function(e,t){const n=new Uint8Array(e.length+t.length-1);for(let u=0;u<e.length;u++)for(let a=0;a<t.length;a++)n[u+a]^=o.mul(e[u],t[a]);return n},r.mod=function(e,t){let n=new Uint8Array(e);for(;n.length-t.length>=0;){const u=n[0];for(let s=0;s<t.length;s++)n[s]^=o.mul(t[s],u);let a=0;for(;a<n.length&&n[a]===0;)a++;n=n.slice(a)}return n},r.generateECPolynomial=function(e){let t=new Uint8Array([1]);for(let n=0;n<e;n++)t=r.mul(t,new Uint8Array([1,o.exp(n)]));return t}})(nt)),nt}var rt,Dt;function ge(){if(Dt)return rt;Dt=1;const r=de();function o(i){this.genPoly=void 0,this.degree=i,this.degree&&this.initialize(this.degree)}return o.prototype.initialize=function(e){this.degree=e,this.genPoly=r.generateECPolynomial(this.degree)},o.prototype.encode=function(e){if(!this.genPoly)throw new Error("Encoder not initialized");const t=new Uint8Array(e.length+this.degree);t.set(e);const n=r.mod(t,this.genPoly),u=this.degree-n.length;if(u>0){const a=new Uint8Array(this.degree);return a.set(n,u),a}return n},rt=o,rt}var ot={},it={},ut={},qt;function Wt(){return qt||(qt=1,ut.isValid=function(o){return!isNaN(o)&&o>=1&&o<=40}),ut}var L={},vt;function Zt(){if(vt)return L;vt=1;const r="[0-9]+",o="[A-Z $%*+\\-./:]+";let i="(?:[u3000-u303F]|[u3040-u309F]|[u30A0-u30FF]|[uFF00-uFFEF]|[u4E00-u9FAF]|[u2605-u2606]|[u2190-u2195]|u203B|[u2010u2015u2018u2019u2025u2026u201Cu201Du2225u2260]|[u0391-u0451]|[u00A7u00A8u00B1u00B4u00D7u00F7])+";i=i.replace(/u/g,"\\u");const e="(?:(?![A-Z0-9 $%*+\\-./:]|"+i+`)(?:.|[\r
|
|
2
|
+
]))+`;L.KANJI=new RegExp(i,"g"),L.BYTE_KANJI=new RegExp("[^A-Z0-9 $%*+\\-./:]+","g"),L.BYTE=new RegExp(e,"g"),L.NUMERIC=new RegExp(r,"g"),L.ALPHANUMERIC=new RegExp(o,"g");const t=new RegExp("^"+i+"$"),n=new RegExp("^"+r+"$"),u=new RegExp("^[A-Z0-9 $%*+\\-./:]+$");return L.testKanji=function(s){return t.test(s)},L.testNumeric=function(s){return n.test(s)},L.testAlphanumeric=function(s){return u.test(s)},L}var _t;function F(){return _t||(_t=1,(function(r){const o=Wt(),i=Zt();r.NUMERIC={id:"Numeric",bit:1,ccBits:[10,12,14]},r.ALPHANUMERIC={id:"Alphanumeric",bit:2,ccBits:[9,11,13]},r.BYTE={id:"Byte",bit:4,ccBits:[8,16,16]},r.KANJI={id:"Kanji",bit:8,ccBits:[8,10,12]},r.MIXED={bit:-1},r.getCharCountIndicator=function(n,u){if(!n.ccBits)throw new Error("Invalid mode: "+n);if(!o.isValid(u))throw new Error("Invalid version: "+u);return u>=1&&u<10?n.ccBits[0]:u<27?n.ccBits[1]:n.ccBits[2]},r.getBestModeForData=function(n){return i.testNumeric(n)?r.NUMERIC:i.testAlphanumeric(n)?r.ALPHANUMERIC:i.testKanji(n)?r.KANJI:r.BYTE},r.toString=function(n){if(n&&n.id)return n.id;throw new Error("Invalid mode")},r.isValid=function(n){return n&&n.bit&&n.ccBits};function e(t){if(typeof t!="string")throw new Error("Param is not a string");switch(t.toLowerCase()){case"numeric":return r.NUMERIC;case"alphanumeric":return r.ALPHANUMERIC;case"kanji":return r.KANJI;case"byte":return r.BYTE;default:throw new Error("Unknown mode: "+t)}}r.from=function(n,u){if(r.isValid(n))return n;try{return e(n)}catch{return u}}})(it)),it}var Ut;function he(){return Ut||(Ut=1,(function(r){const o=U(),i=$t(),e=yt(),t=F(),n=Wt(),u=7973,a=o.getBCHDigit(u);function s(h,f,I){for(let N=1;N<=40;N++)if(f<=r.getCapacity(N,I,h))return N}function c(h,f){return t.getCharCountIndicator(h,f)+4}function d(h,f){let I=0;return h.forEach(function(N){const b=c(N.mode,f);I+=b+N.getBitsLength()}),I}function p(h,f){for(let I=1;I<=40;I++)if(d(h,I)<=r.getCapacity(I,f,t.MIXED))return I}r.from=function(f,I){return n.isValid(f)?parseInt(f,10):I},r.getCapacity=function(f,I,N){if(!n.isValid(f))throw new Error("Invalid QR Code version");typeof N>"u"&&(N=t.BYTE);const b=o.getSymbolTotalCodewords(f),R=i.getTotalCodewordsCount(f,I),M=(b-R)*8;if(N===t.MIXED)return M;const T=M-c(N,f);switch(N){case t.NUMERIC:return Math.floor(T/10*3);case t.ALPHANUMERIC:return Math.floor(T/11*2);case t.KANJI:return Math.floor(T/13);case t.BYTE:default:return Math.floor(T/8)}},r.getBestVersionForData=function(f,I){let N;const b=e.from(I,e.M);if(Array.isArray(f)){if(f.length>1)return p(f,b);if(f.length===0)return 1;N=f[0]}else N=f;return s(N.mode,N.getLength(),b)},r.getEncodedBits=function(f){if(!n.isValid(f)||f<7)throw new Error("Invalid QR Code version");let I=f<<12;for(;o.getBCHDigit(I)-a>=0;)I^=u<<o.getBCHDigit(I)-a;return f<<12|I}})(ot)),ot}var st={},Ft;function me(){if(Ft)return st;Ft=1;const r=U(),o=1335,i=21522,e=r.getBCHDigit(o);return st.getEncodedBits=function(n,u){const a=n.bit<<3|u;let s=a<<10;for(;r.getBCHDigit(s)-e>=0;)s^=o<<r.getBCHDigit(s)-e;return(a<<10|s)^i},st}var at={},ct,kt;function we(){if(kt)return ct;kt=1;const r=F();function o(i){this.mode=r.NUMERIC,this.data=i.toString()}return o.getBitsLength=function(e){return 10*Math.floor(e/3)+(e%3?e%3*3+1:0)},o.prototype.getLength=function(){return this.data.length},o.prototype.getBitsLength=function(){return o.getBitsLength(this.data.length)},o.prototype.write=function(e){let t,n,u;for(t=0;t+3<=this.data.length;t+=3)n=this.data.substr(t,3),u=parseInt(n,10),e.put(u,10);const a=this.data.length-t;a>0&&(n=this.data.substr(t),u=parseInt(n,10),e.put(u,a*3+1))},ct=o,ct}var ft,zt;function ye(){if(zt)return ft;zt=1;const r=F(),o=["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"," ","$","%","*","+","-",".","/",":"];function i(e){this.mode=r.ALPHANUMERIC,this.data=e}return i.getBitsLength=function(t){return 11*Math.floor(t/2)+6*(t%2)},i.prototype.getLength=function(){return this.data.length},i.prototype.getBitsLength=function(){return i.getBitsLength(this.data.length)},i.prototype.write=function(t){let n;for(n=0;n+2<=this.data.length;n+=2){let u=o.indexOf(this.data[n])*45;u+=o.indexOf(this.data[n+1]),t.put(u,11)}this.data.length%2&&t.put(o.indexOf(this.data[n]),6)},ft=i,ft}var lt,Vt;function Ce(){if(Vt)return lt;Vt=1;const r=F();function o(i){this.mode=r.BYTE,typeof i=="string"?this.data=new TextEncoder().encode(i):this.data=new Uint8Array(i)}return o.getBitsLength=function(e){return e*8},o.prototype.getLength=function(){return this.data.length},o.prototype.getBitsLength=function(){return o.getBitsLength(this.data.length)},o.prototype.write=function(i){for(let e=0,t=this.data.length;e<t;e++)i.put(this.data[e],8)},lt=o,lt}var dt,Kt;function Ee(){if(Kt)return dt;Kt=1;const r=F(),o=U();function i(e){this.mode=r.KANJI,this.data=e}return i.getBitsLength=function(t){return t*13},i.prototype.getLength=function(){return this.data.length},i.prototype.getBitsLength=function(){return i.getBitsLength(this.data.length)},i.prototype.write=function(e){let t;for(t=0;t<this.data.length;t++){let n=o.toSJIS(this.data[t]);if(n>=33088&&n<=40956)n-=33088;else if(n>=57408&&n<=60351)n-=49472;else throw new Error("Invalid SJIS character: "+this.data[t]+`
|
|
3
|
+
Make sure your charset is UTF-8`);n=(n>>>8&255)*192+(n&255),e.put(n,13)}},dt=i,dt}var gt={exports:{}},Ht;function pe(){return Ht||(Ht=1,(function(r){var o={single_source_shortest_paths:function(i,e,t){var n={},u={};u[e]=0;var a=o.PriorityQueue.make();a.push(e,0);for(var s,c,d,p,h,f,I,N,b;!a.empty();){s=a.pop(),c=s.value,p=s.cost,h=i[c]||{};for(d in h)h.hasOwnProperty(d)&&(f=h[d],I=p+f,N=u[d],b=typeof u[d]>"u",(b||N>I)&&(u[d]=I,a.push(d,I),n[d]=c))}if(typeof t<"u"&&typeof u[t]>"u"){var R=["Could not find a path from ",e," to ",t,"."].join("");throw new Error(R)}return n},extract_shortest_path_from_predecessor_list:function(i,e){for(var t=[],n=e;n;)t.push(n),i[n],n=i[n];return t.reverse(),t},find_path:function(i,e,t){var n=o.single_source_shortest_paths(i,e,t);return o.extract_shortest_path_from_predecessor_list(n,t)},PriorityQueue:{make:function(i){var e=o.PriorityQueue,t={},n;i=i||{};for(n in e)e.hasOwnProperty(n)&&(t[n]=e[n]);return t.queue=[],t.sorter=i.sorter||e.default_sorter,t},default_sorter:function(i,e){return i.cost-e.cost},push:function(i,e){var t={value:i,cost:e};this.queue.push(t),this.queue.sort(this.sorter)},pop:function(){return this.queue.shift()},empty:function(){return this.queue.length===0}}};r.exports=o})(gt)),gt.exports}var Ot;function Be(){return Ot||(Ot=1,(function(r){const o=F(),i=we(),e=ye(),t=Ce(),n=Ee(),u=Zt(),a=U(),s=pe();function c(R){return unescape(encodeURIComponent(R)).length}function d(R,M,T){const B=[];let S;for(;(S=R.exec(T))!==null;)B.push({data:S[0],index:S.index,mode:M,length:S[0].length});return B}function p(R){const M=d(u.NUMERIC,o.NUMERIC,R),T=d(u.ALPHANUMERIC,o.ALPHANUMERIC,R);let B,S;return a.isKanjiModeEnabled()?(B=d(u.BYTE,o.BYTE,R),S=d(u.KANJI,o.KANJI,R)):(B=d(u.BYTE_KANJI,o.BYTE,R),S=[]),M.concat(T,B,S).sort(function(C,y){return C.index-y.index}).map(function(C){return{data:C.data,mode:C.mode,length:C.length}})}function h(R,M){switch(M){case o.NUMERIC:return i.getBitsLength(R);case o.ALPHANUMERIC:return e.getBitsLength(R);case o.KANJI:return n.getBitsLength(R);case o.BYTE:return t.getBitsLength(R)}}function f(R){return R.reduce(function(M,T){const B=M.length-1>=0?M[M.length-1]:null;return B&&B.mode===T.mode?(M[M.length-1].data+=T.data,M):(M.push(T),M)},[])}function I(R){const M=[];for(let T=0;T<R.length;T++){const B=R[T];switch(B.mode){case o.NUMERIC:M.push([B,{data:B.data,mode:o.ALPHANUMERIC,length:B.length},{data:B.data,mode:o.BYTE,length:B.length}]);break;case o.ALPHANUMERIC:M.push([B,{data:B.data,mode:o.BYTE,length:B.length}]);break;case o.KANJI:M.push([B,{data:B.data,mode:o.BYTE,length:c(B.data)}]);break;case o.BYTE:M.push([{data:B.data,mode:o.BYTE,length:c(B.data)}])}}return M}function N(R,M){const T={},B={start:{}};let S=["start"];for(let g=0;g<R.length;g++){const C=R[g],y=[];for(let l=0;l<C.length;l++){const A=C[l],m=""+g+l;y.push(m),T[m]={node:A,lastCount:0},B[m]={};for(let E=0;E<S.length;E++){const w=S[E];T[w]&&T[w].node.mode===A.mode?(B[w][m]=h(T[w].lastCount+A.length,A.mode)-h(T[w].lastCount,A.mode),T[w].lastCount+=A.length):(T[w]&&(T[w].lastCount=A.length),B[w][m]=h(A.length,A.mode)+4+o.getCharCountIndicator(A.mode,M))}}S=y}for(let g=0;g<S.length;g++)B[S[g]].end=0;return{map:B,table:T}}function b(R,M){let T;const B=o.getBestModeForData(R);if(T=o.from(M,B),T!==o.BYTE&&T.bit<B.bit)throw new Error('"'+R+'" cannot be encoded with mode '+o.toString(T)+`.
|
|
4
|
+
Suggested mode is: `+o.toString(B));switch(T===o.KANJI&&!a.isKanjiModeEnabled()&&(T=o.BYTE),T){case o.NUMERIC:return new i(R);case o.ALPHANUMERIC:return new e(R);case o.KANJI:return new n(R);case o.BYTE:return new t(R)}}r.fromArray=function(M){return M.reduce(function(T,B){return typeof B=="string"?T.push(b(B,null)):B.data&&T.push(b(B.data,B.mode)),T},[])},r.fromString=function(M,T){const B=p(M,a.isKanjiModeEnabled()),S=I(B),g=N(S,T),C=s.find_path(g.map,"start","end"),y=[];for(let l=1;l<C.length-1;l++)y.push(g.table[C[l]].node);return r.fromArray(f(y))},r.rawSplit=function(M){return r.fromArray(p(M,a.isKanjiModeEnabled()))}})(at)),at}var jt;function Ae(){if(jt)return $;jt=1;const r=U(),o=yt(),i=ue(),e=se(),t=ae(),n=ce(),u=fe(),a=$t(),s=ge(),c=he(),d=me(),p=F(),h=Be();function f(g,C){const y=g.size,l=n.getPositions(C);for(let A=0;A<l.length;A++){const m=l[A][0],E=l[A][1];for(let w=-1;w<=7;w++)if(!(m+w<=-1||y<=m+w))for(let P=-1;P<=7;P++)E+P<=-1||y<=E+P||(w>=0&&w<=6&&(P===0||P===6)||P>=0&&P<=6&&(w===0||w===6)||w>=2&&w<=4&&P>=2&&P<=4?g.set(m+w,E+P,!0,!0):g.set(m+w,E+P,!1,!0))}}function I(g){const C=g.size;for(let y=8;y<C-8;y++){const l=y%2===0;g.set(y,6,l,!0),g.set(6,y,l,!0)}}function N(g,C){const y=t.getPositions(C);for(let l=0;l<y.length;l++){const A=y[l][0],m=y[l][1];for(let E=-2;E<=2;E++)for(let w=-2;w<=2;w++)E===-2||E===2||w===-2||w===2||E===0&&w===0?g.set(A+E,m+w,!0,!0):g.set(A+E,m+w,!1,!0)}}function b(g,C){const y=g.size,l=c.getEncodedBits(C);let A,m,E;for(let w=0;w<18;w++)A=Math.floor(w/3),m=w%3+y-8-3,E=(l>>w&1)===1,g.set(A,m,E,!0),g.set(m,A,E,!0)}function R(g,C,y){const l=g.size,A=d.getEncodedBits(C,y);let m,E;for(m=0;m<15;m++)E=(A>>m&1)===1,m<6?g.set(m,8,E,!0):m<8?g.set(m+1,8,E,!0):g.set(l-15+m,8,E,!0),m<8?g.set(8,l-m-1,E,!0):m<9?g.set(8,15-m-1+1,E,!0):g.set(8,15-m-1,E,!0);g.set(l-8,8,1,!0)}function M(g,C){const y=g.size;let l=-1,A=y-1,m=7,E=0;for(let w=y-1;w>0;w-=2)for(w===6&&w--;;){for(let P=0;P<2;P++)if(!g.isReserved(A,w-P)){let v=!1;E<C.length&&(v=(C[E]>>>m&1)===1),g.set(A,w-P,v),m--,m===-1&&(E++,m=7)}if(A+=l,A<0||y<=A){A-=l,l=-l;break}}}function T(g,C,y){const l=new i;y.forEach(function(P){l.put(P.mode.bit,4),l.put(P.getLength(),p.getCharCountIndicator(P.mode,g)),P.write(l)});const A=r.getSymbolTotalCodewords(g),m=a.getTotalCodewordsCount(g,C),E=(A-m)*8;for(l.getLengthInBits()+4<=E&&l.put(0,4);l.getLengthInBits()%8!==0;)l.putBit(0);const w=(E-l.getLengthInBits())/8;for(let P=0;P<w;P++)l.put(P%2?17:236,8);return B(l,g,C)}function B(g,C,y){const l=r.getSymbolTotalCodewords(C),A=a.getTotalCodewordsCount(C,y),m=l-A,E=a.getBlocksCount(C,y),w=l%E,P=E-w,v=Math.floor(l/E),V=Math.floor(m/E),te=V+1,Ct=v-V,ee=new s(Ct);let j=0;const H=new Array(E),Et=new Array(E);let J=0;const ne=new Uint8Array(g.buffer);for(let k=0;k<E;k++){const G=k<P?V:te;H[k]=ne.slice(j,j+G),Et[k]=ee.encode(H[k]),j+=G,J=Math.max(J,G)}const Y=new Uint8Array(l);let pt=0,D,q;for(D=0;D<J;D++)for(q=0;q<E;q++)D<H[q].length&&(Y[pt++]=H[q][D]);for(D=0;D<Ct;D++)for(q=0;q<E;q++)Y[pt++]=Et[q][D];return Y}function S(g,C,y,l){let A;if(Array.isArray(g))A=h.fromArray(g);else if(typeof g=="string"){let v=C;if(!v){const V=h.rawSplit(g);v=c.getBestVersionForData(V,y)}A=h.fromString(g,v||40)}else throw new Error("Invalid data");const m=c.getBestVersionForData(A,y);if(!m)throw new Error("The amount of data is too big to be stored in a QR Code");if(!C)C=m;else if(C<m)throw new Error(`
|
|
5
|
+
The chosen QR Code version cannot contain this amount of data.
|
|
6
|
+
Minimum version required to store current data is: `+m+`.
|
|
7
|
+
`);const E=T(C,y,A),w=r.getSymbolSize(C),P=new e(w);return f(P,C),I(P),N(P,C),R(P,y,0),C>=7&&b(P,C),M(P,E),isNaN(l)&&(l=u.getBestMask(P,R.bind(null,P,y))),u.applyMask(l,P),R(P,y,l),{modules:P,version:C,errorCorrectionLevel:y,maskPattern:l,segments:A}}return $.create=function(C,y){if(typeof C>"u"||C==="")throw new Error("No input text");let l=o.M,A,m;return typeof y<"u"&&(l=o.from(y.errorCorrectionLevel,o.M),A=c.from(y.version),m=u.from(y.maskPattern),y.toSJISFunc&&r.setToSJISFunction(y.toSJISFunc)),S(C,A,l,m)},$}var ht={},mt={},Jt;function Xt(){return Jt||(Jt=1,(function(r){function o(i){if(typeof i=="number"&&(i=i.toString()),typeof i!="string")throw new Error("Color should be defined as hex string");let e=i.slice().replace("#","").split("");if(e.length<3||e.length===5||e.length>8)throw new Error("Invalid hex color: "+i);(e.length===3||e.length===4)&&(e=Array.prototype.concat.apply([],e.map(function(n){return[n,n]}))),e.length===6&&e.push("F","F");const t=parseInt(e.join(""),16);return{r:t>>24&255,g:t>>16&255,b:t>>8&255,a:t&255,hex:"#"+e.slice(0,6).join("")}}r.getOptions=function(e){e||(e={}),e.color||(e.color={});const t=typeof e.margin>"u"||e.margin===null||e.margin<0?4:e.margin,n=e.width&&e.width>=21?e.width:void 0,u=e.scale||4;return{width:n,scale:n?4:u,margin:t,color:{dark:o(e.color.dark||"#000000ff"),light:o(e.color.light||"#ffffffff")},type:e.type,rendererOpts:e.rendererOpts||{}}},r.getScale=function(e,t){return t.width&&t.width>=e+t.margin*2?t.width/(e+t.margin*2):t.scale},r.getImageWidth=function(e,t){const n=r.getScale(e,t);return Math.floor((e+t.margin*2)*n)},r.qrToImageData=function(e,t,n){const u=t.modules.size,a=t.modules.data,s=r.getScale(u,n),c=Math.floor((u+n.margin*2)*s),d=n.margin*s,p=[n.color.light,n.color.dark];for(let h=0;h<c;h++)for(let f=0;f<c;f++){let I=(h*c+f)*4,N=n.color.light;if(h>=d&&f>=d&&h<c-d&&f<c-d){const b=Math.floor((h-d)/s),R=Math.floor((f-d)/s);N=p[a[b*u+R]?1:0]}e[I++]=N.r,e[I++]=N.g,e[I++]=N.b,e[I]=N.a}}})(mt)),mt}var Yt;function Re(){return Yt||(Yt=1,(function(r){const o=Xt();function i(t,n,u){t.clearRect(0,0,n.width,n.height),n.style||(n.style={}),n.height=u,n.width=u,n.style.height=u+"px",n.style.width=u+"px"}function e(){try{return document.createElement("canvas")}catch{throw new Error("You need to specify a canvas element")}}r.render=function(n,u,a){let s=a,c=u;typeof s>"u"&&(!u||!u.getContext)&&(s=u,u=void 0),u||(c=e()),s=o.getOptions(s);const d=o.getImageWidth(n.modules.size,s),p=c.getContext("2d"),h=p.createImageData(d,d);return o.qrToImageData(h.data,n,s),i(p,c,d),p.putImageData(h,0,0),c},r.renderToDataURL=function(n,u,a){let s=a;typeof s>"u"&&(!u||!u.getContext)&&(s=u,u=void 0),s||(s={});const c=r.render(n,u,s),d=s.type||"image/png",p=s.rendererOpts||{};return c.toDataURL(d,p.quality)}})(ht)),ht}var wt={},Gt;function Te(){if(Gt)return wt;Gt=1;const r=Xt();function o(t,n){const u=t.a/255,a=n+'="'+t.hex+'"';return u<1?a+" "+n+'-opacity="'+u.toFixed(2).slice(1)+'"':a}function i(t,n,u){let a=t+n;return typeof u<"u"&&(a+=" "+u),a}function e(t,n,u){let a="",s=0,c=!1,d=0;for(let p=0;p<t.length;p++){const h=Math.floor(p%n),f=Math.floor(p/n);!h&&!c&&(c=!0),t[p]?(d++,p>0&&h>0&&t[p-1]||(a+=c?i("M",h+u,.5+f+u):i("m",s,0),s=0,c=!1),h+1<n&&t[p+1]||(a+=i("h",d),d=0)):s++}return a}return wt.render=function(n,u,a){const s=r.getOptions(u),c=n.modules.size,d=n.modules.data,p=c+s.margin*2,h=s.color.light.a?"<path "+o(s.color.light,"fill")+' d="M0 0h'+p+"v"+p+'H0z"/>':"",f="<path "+o(s.color.dark,"stroke")+' d="'+e(d,c,s.margin)+'"/>',I='viewBox="0 0 '+p+" "+p+'"',b='<svg xmlns="http://www.w3.org/2000/svg" '+(s.width?'width="'+s.width+'" height="'+s.width+'" ':"")+I+' shape-rendering="crispEdges">'+h+f+`</svg>
|
|
8
|
+
`;return typeof a=="function"&&a(null,b),b},wt}var Qt;function Pe(){if(Qt)return z;Qt=1;const r=ie(),o=Ae(),i=Re(),e=Te();function t(n,u,a,s,c){const d=[].slice.call(arguments,1),p=d.length,h=typeof d[p-1]=="function";if(!h&&!r())throw new Error("Callback required as last argument");if(h){if(p<2)throw new Error("Too few arguments provided");p===2?(c=a,a=u,u=s=void 0):p===3&&(u.getContext&&typeof c>"u"?(c=s,s=void 0):(c=s,s=a,a=u,u=void 0))}else{if(p<1)throw new Error("Too few arguments provided");return p===1?(a=u,u=s=void 0):p===2&&!u.getContext&&(s=a,a=u,u=void 0),new Promise(function(f,I){try{const N=o.create(a,s);f(n(N,u,s))}catch(N){I(N)}})}try{const f=o.create(a,s);c(null,n(f,u,s))}catch(f){c(f)}}return z.create=o.create,z.toCanvas=t.bind(null,i.render),z.toDataURL=t.bind(null,i.renderToDataURL),z.toString=t.bind(null,function(n,u,a){return e.render(n,a)}),z}var xt=Pe();const Ie=oe(xt),Ne=re({__proto__:null,default:Ie},[xt]);exports.browser=Ne;
|