@ericchen1990/pano-view 2.2.2 → 2.3.0
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/README.md +119 -2
- package/README.zh-CN.md +85 -1
- package/dist/index.cjs +3476 -560
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +76 -2
- package/dist/index.d.ts +76 -2
- package/dist/index.mjs +3267 -334
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -2
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,2242 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
9
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
|
|
28
|
+
// ../../node_modules/.pnpm/howler@2.2.4/node_modules/howler/dist/howler.js
|
|
29
|
+
var require_howler = __commonJS({
|
|
30
|
+
"../../node_modules/.pnpm/howler@2.2.4/node_modules/howler/dist/howler.js"(exports) {
|
|
31
|
+
"use strict";
|
|
32
|
+
(function() {
|
|
33
|
+
"use strict";
|
|
34
|
+
var HowlerGlobal2 = function() {
|
|
35
|
+
this.init();
|
|
36
|
+
};
|
|
37
|
+
HowlerGlobal2.prototype = {
|
|
38
|
+
/**
|
|
39
|
+
* Initialize the global Howler object.
|
|
40
|
+
* @return {Howler}
|
|
41
|
+
*/
|
|
42
|
+
init: function() {
|
|
43
|
+
var self = this || Howler3;
|
|
44
|
+
self._counter = 1e3;
|
|
45
|
+
self._html5AudioPool = [];
|
|
46
|
+
self.html5PoolSize = 10;
|
|
47
|
+
self._codecs = {};
|
|
48
|
+
self._howls = [];
|
|
49
|
+
self._muted = false;
|
|
50
|
+
self._volume = 1;
|
|
51
|
+
self._canPlayEvent = "canplaythrough";
|
|
52
|
+
self._navigator = typeof window !== "undefined" && window.navigator ? window.navigator : null;
|
|
53
|
+
self.masterGain = null;
|
|
54
|
+
self.noAudio = false;
|
|
55
|
+
self.usingWebAudio = true;
|
|
56
|
+
self.autoSuspend = true;
|
|
57
|
+
self.ctx = null;
|
|
58
|
+
self.autoUnlock = true;
|
|
59
|
+
self._setup();
|
|
60
|
+
return self;
|
|
61
|
+
},
|
|
62
|
+
/**
|
|
63
|
+
* Get/set the global volume for all sounds.
|
|
64
|
+
* @param {Float} vol Volume from 0.0 to 1.0.
|
|
65
|
+
* @return {Howler/Float} Returns self or current volume.
|
|
66
|
+
*/
|
|
67
|
+
volume: function(vol) {
|
|
68
|
+
var self = this || Howler3;
|
|
69
|
+
vol = parseFloat(vol);
|
|
70
|
+
if (!self.ctx) {
|
|
71
|
+
setupAudioContext();
|
|
72
|
+
}
|
|
73
|
+
if (typeof vol !== "undefined" && vol >= 0 && vol <= 1) {
|
|
74
|
+
self._volume = vol;
|
|
75
|
+
if (self._muted) {
|
|
76
|
+
return self;
|
|
77
|
+
}
|
|
78
|
+
if (self.usingWebAudio) {
|
|
79
|
+
self.masterGain.gain.setValueAtTime(vol, Howler3.ctx.currentTime);
|
|
80
|
+
}
|
|
81
|
+
for (var i = 0; i < self._howls.length; i++) {
|
|
82
|
+
if (!self._howls[i]._webAudio) {
|
|
83
|
+
var ids = self._howls[i]._getSoundIds();
|
|
84
|
+
for (var j = 0; j < ids.length; j++) {
|
|
85
|
+
var sound = self._howls[i]._soundById(ids[j]);
|
|
86
|
+
if (sound && sound._node) {
|
|
87
|
+
sound._node.volume = sound._volume * vol;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return self;
|
|
93
|
+
}
|
|
94
|
+
return self._volume;
|
|
95
|
+
},
|
|
96
|
+
/**
|
|
97
|
+
* Handle muting and unmuting globally.
|
|
98
|
+
* @param {Boolean} muted Is muted or not.
|
|
99
|
+
*/
|
|
100
|
+
mute: function(muted) {
|
|
101
|
+
var self = this || Howler3;
|
|
102
|
+
if (!self.ctx) {
|
|
103
|
+
setupAudioContext();
|
|
104
|
+
}
|
|
105
|
+
self._muted = muted;
|
|
106
|
+
if (self.usingWebAudio) {
|
|
107
|
+
self.masterGain.gain.setValueAtTime(muted ? 0 : self._volume, Howler3.ctx.currentTime);
|
|
108
|
+
}
|
|
109
|
+
for (var i = 0; i < self._howls.length; i++) {
|
|
110
|
+
if (!self._howls[i]._webAudio) {
|
|
111
|
+
var ids = self._howls[i]._getSoundIds();
|
|
112
|
+
for (var j = 0; j < ids.length; j++) {
|
|
113
|
+
var sound = self._howls[i]._soundById(ids[j]);
|
|
114
|
+
if (sound && sound._node) {
|
|
115
|
+
sound._node.muted = muted ? true : sound._muted;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return self;
|
|
121
|
+
},
|
|
122
|
+
/**
|
|
123
|
+
* Handle stopping all sounds globally.
|
|
124
|
+
*/
|
|
125
|
+
stop: function() {
|
|
126
|
+
var self = this || Howler3;
|
|
127
|
+
for (var i = 0; i < self._howls.length; i++) {
|
|
128
|
+
self._howls[i].stop();
|
|
129
|
+
}
|
|
130
|
+
return self;
|
|
131
|
+
},
|
|
132
|
+
/**
|
|
133
|
+
* Unload and destroy all currently loaded Howl objects.
|
|
134
|
+
* @return {Howler}
|
|
135
|
+
*/
|
|
136
|
+
unload: function() {
|
|
137
|
+
var self = this || Howler3;
|
|
138
|
+
for (var i = self._howls.length - 1; i >= 0; i--) {
|
|
139
|
+
self._howls[i].unload();
|
|
140
|
+
}
|
|
141
|
+
if (self.usingWebAudio && self.ctx && typeof self.ctx.close !== "undefined") {
|
|
142
|
+
self.ctx.close();
|
|
143
|
+
self.ctx = null;
|
|
144
|
+
setupAudioContext();
|
|
145
|
+
}
|
|
146
|
+
return self;
|
|
147
|
+
},
|
|
148
|
+
/**
|
|
149
|
+
* Check for codec support of specific extension.
|
|
150
|
+
* @param {String} ext Audio file extention.
|
|
151
|
+
* @return {Boolean}
|
|
152
|
+
*/
|
|
153
|
+
codecs: function(ext) {
|
|
154
|
+
return (this || Howler3)._codecs[ext.replace(/^x-/, "")];
|
|
155
|
+
},
|
|
156
|
+
/**
|
|
157
|
+
* Setup various state values for global tracking.
|
|
158
|
+
* @return {Howler}
|
|
159
|
+
*/
|
|
160
|
+
_setup: function() {
|
|
161
|
+
var self = this || Howler3;
|
|
162
|
+
self.state = self.ctx ? self.ctx.state || "suspended" : "suspended";
|
|
163
|
+
self._autoSuspend();
|
|
164
|
+
if (!self.usingWebAudio) {
|
|
165
|
+
if (typeof Audio !== "undefined") {
|
|
166
|
+
try {
|
|
167
|
+
var test = new Audio();
|
|
168
|
+
if (typeof test.oncanplaythrough === "undefined") {
|
|
169
|
+
self._canPlayEvent = "canplay";
|
|
170
|
+
}
|
|
171
|
+
} catch (e) {
|
|
172
|
+
self.noAudio = true;
|
|
173
|
+
}
|
|
174
|
+
} else {
|
|
175
|
+
self.noAudio = true;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
try {
|
|
179
|
+
var test = new Audio();
|
|
180
|
+
if (test.muted) {
|
|
181
|
+
self.noAudio = true;
|
|
182
|
+
}
|
|
183
|
+
} catch (e) {
|
|
184
|
+
}
|
|
185
|
+
if (!self.noAudio) {
|
|
186
|
+
self._setupCodecs();
|
|
187
|
+
}
|
|
188
|
+
return self;
|
|
189
|
+
},
|
|
190
|
+
/**
|
|
191
|
+
* Check for browser support for various codecs and cache the results.
|
|
192
|
+
* @return {Howler}
|
|
193
|
+
*/
|
|
194
|
+
_setupCodecs: function() {
|
|
195
|
+
var self = this || Howler3;
|
|
196
|
+
var audioTest = null;
|
|
197
|
+
try {
|
|
198
|
+
audioTest = typeof Audio !== "undefined" ? new Audio() : null;
|
|
199
|
+
} catch (err) {
|
|
200
|
+
return self;
|
|
201
|
+
}
|
|
202
|
+
if (!audioTest || typeof audioTest.canPlayType !== "function") {
|
|
203
|
+
return self;
|
|
204
|
+
}
|
|
205
|
+
var mpegTest = audioTest.canPlayType("audio/mpeg;").replace(/^no$/, "");
|
|
206
|
+
var ua = self._navigator ? self._navigator.userAgent : "";
|
|
207
|
+
var checkOpera = ua.match(/OPR\/(\d+)/g);
|
|
208
|
+
var isOldOpera = checkOpera && parseInt(checkOpera[0].split("/")[1], 10) < 33;
|
|
209
|
+
var checkSafari = ua.indexOf("Safari") !== -1 && ua.indexOf("Chrome") === -1;
|
|
210
|
+
var safariVersion = ua.match(/Version\/(.*?) /);
|
|
211
|
+
var isOldSafari = checkSafari && safariVersion && parseInt(safariVersion[1], 10) < 15;
|
|
212
|
+
self._codecs = {
|
|
213
|
+
mp3: !!(!isOldOpera && (mpegTest || audioTest.canPlayType("audio/mp3;").replace(/^no$/, ""))),
|
|
214
|
+
mpeg: !!mpegTest,
|
|
215
|
+
opus: !!audioTest.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/, ""),
|
|
216
|
+
ogg: !!audioTest.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ""),
|
|
217
|
+
oga: !!audioTest.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ""),
|
|
218
|
+
wav: !!(audioTest.canPlayType('audio/wav; codecs="1"') || audioTest.canPlayType("audio/wav")).replace(/^no$/, ""),
|
|
219
|
+
aac: !!audioTest.canPlayType("audio/aac;").replace(/^no$/, ""),
|
|
220
|
+
caf: !!audioTest.canPlayType("audio/x-caf;").replace(/^no$/, ""),
|
|
221
|
+
m4a: !!(audioTest.canPlayType("audio/x-m4a;") || audioTest.canPlayType("audio/m4a;") || audioTest.canPlayType("audio/aac;")).replace(/^no$/, ""),
|
|
222
|
+
m4b: !!(audioTest.canPlayType("audio/x-m4b;") || audioTest.canPlayType("audio/m4b;") || audioTest.canPlayType("audio/aac;")).replace(/^no$/, ""),
|
|
223
|
+
mp4: !!(audioTest.canPlayType("audio/x-mp4;") || audioTest.canPlayType("audio/mp4;") || audioTest.canPlayType("audio/aac;")).replace(/^no$/, ""),
|
|
224
|
+
weba: !!(!isOldSafari && audioTest.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, "")),
|
|
225
|
+
webm: !!(!isOldSafari && audioTest.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/, "")),
|
|
226
|
+
dolby: !!audioTest.canPlayType('audio/mp4; codecs="ec-3"').replace(/^no$/, ""),
|
|
227
|
+
flac: !!(audioTest.canPlayType("audio/x-flac;") || audioTest.canPlayType("audio/flac;")).replace(/^no$/, "")
|
|
228
|
+
};
|
|
229
|
+
return self;
|
|
230
|
+
},
|
|
231
|
+
/**
|
|
232
|
+
* Some browsers/devices will only allow audio to be played after a user interaction.
|
|
233
|
+
* Attempt to automatically unlock audio on the first user interaction.
|
|
234
|
+
* Concept from: http://paulbakaus.com/tutorials/html5/web-audio-on-ios/
|
|
235
|
+
* @return {Howler}
|
|
236
|
+
*/
|
|
237
|
+
_unlockAudio: function() {
|
|
238
|
+
var self = this || Howler3;
|
|
239
|
+
if (self._audioUnlocked || !self.ctx) {
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
self._audioUnlocked = false;
|
|
243
|
+
self.autoUnlock = false;
|
|
244
|
+
if (!self._mobileUnloaded && self.ctx.sampleRate !== 44100) {
|
|
245
|
+
self._mobileUnloaded = true;
|
|
246
|
+
self.unload();
|
|
247
|
+
}
|
|
248
|
+
self._scratchBuffer = self.ctx.createBuffer(1, 1, 22050);
|
|
249
|
+
var unlock = function(e) {
|
|
250
|
+
while (self._html5AudioPool.length < self.html5PoolSize) {
|
|
251
|
+
try {
|
|
252
|
+
var audioNode = new Audio();
|
|
253
|
+
audioNode._unlocked = true;
|
|
254
|
+
self._releaseHtml5Audio(audioNode);
|
|
255
|
+
} catch (e2) {
|
|
256
|
+
self.noAudio = true;
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
for (var i = 0; i < self._howls.length; i++) {
|
|
261
|
+
if (!self._howls[i]._webAudio) {
|
|
262
|
+
var ids = self._howls[i]._getSoundIds();
|
|
263
|
+
for (var j = 0; j < ids.length; j++) {
|
|
264
|
+
var sound = self._howls[i]._soundById(ids[j]);
|
|
265
|
+
if (sound && sound._node && !sound._node._unlocked) {
|
|
266
|
+
sound._node._unlocked = true;
|
|
267
|
+
sound._node.load();
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
self._autoResume();
|
|
273
|
+
var source = self.ctx.createBufferSource();
|
|
274
|
+
source.buffer = self._scratchBuffer;
|
|
275
|
+
source.connect(self.ctx.destination);
|
|
276
|
+
if (typeof source.start === "undefined") {
|
|
277
|
+
source.noteOn(0);
|
|
278
|
+
} else {
|
|
279
|
+
source.start(0);
|
|
280
|
+
}
|
|
281
|
+
if (typeof self.ctx.resume === "function") {
|
|
282
|
+
self.ctx.resume();
|
|
283
|
+
}
|
|
284
|
+
source.onended = function() {
|
|
285
|
+
source.disconnect(0);
|
|
286
|
+
self._audioUnlocked = true;
|
|
287
|
+
document.removeEventListener("touchstart", unlock, true);
|
|
288
|
+
document.removeEventListener("touchend", unlock, true);
|
|
289
|
+
document.removeEventListener("click", unlock, true);
|
|
290
|
+
document.removeEventListener("keydown", unlock, true);
|
|
291
|
+
for (var i2 = 0; i2 < self._howls.length; i2++) {
|
|
292
|
+
self._howls[i2]._emit("unlock");
|
|
293
|
+
}
|
|
294
|
+
};
|
|
295
|
+
};
|
|
296
|
+
document.addEventListener("touchstart", unlock, true);
|
|
297
|
+
document.addEventListener("touchend", unlock, true);
|
|
298
|
+
document.addEventListener("click", unlock, true);
|
|
299
|
+
document.addEventListener("keydown", unlock, true);
|
|
300
|
+
return self;
|
|
301
|
+
},
|
|
302
|
+
/**
|
|
303
|
+
* Get an unlocked HTML5 Audio object from the pool. If none are left,
|
|
304
|
+
* return a new Audio object and throw a warning.
|
|
305
|
+
* @return {Audio} HTML5 Audio object.
|
|
306
|
+
*/
|
|
307
|
+
_obtainHtml5Audio: function() {
|
|
308
|
+
var self = this || Howler3;
|
|
309
|
+
if (self._html5AudioPool.length) {
|
|
310
|
+
return self._html5AudioPool.pop();
|
|
311
|
+
}
|
|
312
|
+
var testPlay = new Audio().play();
|
|
313
|
+
if (testPlay && typeof Promise !== "undefined" && (testPlay instanceof Promise || typeof testPlay.then === "function")) {
|
|
314
|
+
testPlay.catch(function() {
|
|
315
|
+
console.warn("HTML5 Audio pool exhausted, returning potentially locked audio object.");
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
return new Audio();
|
|
319
|
+
},
|
|
320
|
+
/**
|
|
321
|
+
* Return an activated HTML5 Audio object to the pool.
|
|
322
|
+
* @return {Howler}
|
|
323
|
+
*/
|
|
324
|
+
_releaseHtml5Audio: function(audio) {
|
|
325
|
+
var self = this || Howler3;
|
|
326
|
+
if (audio._unlocked) {
|
|
327
|
+
self._html5AudioPool.push(audio);
|
|
328
|
+
}
|
|
329
|
+
return self;
|
|
330
|
+
},
|
|
331
|
+
/**
|
|
332
|
+
* Automatically suspend the Web Audio AudioContext after no sound has played for 30 seconds.
|
|
333
|
+
* This saves processing/energy and fixes various browser-specific bugs with audio getting stuck.
|
|
334
|
+
* @return {Howler}
|
|
335
|
+
*/
|
|
336
|
+
_autoSuspend: function() {
|
|
337
|
+
var self = this;
|
|
338
|
+
if (!self.autoSuspend || !self.ctx || typeof self.ctx.suspend === "undefined" || !Howler3.usingWebAudio) {
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
for (var i = 0; i < self._howls.length; i++) {
|
|
342
|
+
if (self._howls[i]._webAudio) {
|
|
343
|
+
for (var j = 0; j < self._howls[i]._sounds.length; j++) {
|
|
344
|
+
if (!self._howls[i]._sounds[j]._paused) {
|
|
345
|
+
return self;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
if (self._suspendTimer) {
|
|
351
|
+
clearTimeout(self._suspendTimer);
|
|
352
|
+
}
|
|
353
|
+
self._suspendTimer = setTimeout(function() {
|
|
354
|
+
if (!self.autoSuspend) {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
self._suspendTimer = null;
|
|
358
|
+
self.state = "suspending";
|
|
359
|
+
var handleSuspension = function() {
|
|
360
|
+
self.state = "suspended";
|
|
361
|
+
if (self._resumeAfterSuspend) {
|
|
362
|
+
delete self._resumeAfterSuspend;
|
|
363
|
+
self._autoResume();
|
|
364
|
+
}
|
|
365
|
+
};
|
|
366
|
+
self.ctx.suspend().then(handleSuspension, handleSuspension);
|
|
367
|
+
}, 3e4);
|
|
368
|
+
return self;
|
|
369
|
+
},
|
|
370
|
+
/**
|
|
371
|
+
* Automatically resume the Web Audio AudioContext when a new sound is played.
|
|
372
|
+
* @return {Howler}
|
|
373
|
+
*/
|
|
374
|
+
_autoResume: function() {
|
|
375
|
+
var self = this;
|
|
376
|
+
if (!self.ctx || typeof self.ctx.resume === "undefined" || !Howler3.usingWebAudio) {
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
if (self.state === "running" && self.ctx.state !== "interrupted" && self._suspendTimer) {
|
|
380
|
+
clearTimeout(self._suspendTimer);
|
|
381
|
+
self._suspendTimer = null;
|
|
382
|
+
} else if (self.state === "suspended" || self.state === "running" && self.ctx.state === "interrupted") {
|
|
383
|
+
self.ctx.resume().then(function() {
|
|
384
|
+
self.state = "running";
|
|
385
|
+
for (var i = 0; i < self._howls.length; i++) {
|
|
386
|
+
self._howls[i]._emit("resume");
|
|
387
|
+
}
|
|
388
|
+
});
|
|
389
|
+
if (self._suspendTimer) {
|
|
390
|
+
clearTimeout(self._suspendTimer);
|
|
391
|
+
self._suspendTimer = null;
|
|
392
|
+
}
|
|
393
|
+
} else if (self.state === "suspending") {
|
|
394
|
+
self._resumeAfterSuspend = true;
|
|
395
|
+
}
|
|
396
|
+
return self;
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
var Howler3 = new HowlerGlobal2();
|
|
400
|
+
var Howl3 = function(o) {
|
|
401
|
+
var self = this;
|
|
402
|
+
if (!o.src || o.src.length === 0) {
|
|
403
|
+
console.error("An array of source files must be passed with any new Howl.");
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
self.init(o);
|
|
407
|
+
};
|
|
408
|
+
Howl3.prototype = {
|
|
409
|
+
/**
|
|
410
|
+
* Initialize a new Howl group object.
|
|
411
|
+
* @param {Object} o Passed in properties for this group.
|
|
412
|
+
* @return {Howl}
|
|
413
|
+
*/
|
|
414
|
+
init: function(o) {
|
|
415
|
+
var self = this;
|
|
416
|
+
if (!Howler3.ctx) {
|
|
417
|
+
setupAudioContext();
|
|
418
|
+
}
|
|
419
|
+
self._autoplay = o.autoplay || false;
|
|
420
|
+
self._format = typeof o.format !== "string" ? o.format : [o.format];
|
|
421
|
+
self._html5 = o.html5 || false;
|
|
422
|
+
self._muted = o.mute || false;
|
|
423
|
+
self._loop = o.loop || false;
|
|
424
|
+
self._pool = o.pool || 5;
|
|
425
|
+
self._preload = typeof o.preload === "boolean" || o.preload === "metadata" ? o.preload : true;
|
|
426
|
+
self._rate = o.rate || 1;
|
|
427
|
+
self._sprite = o.sprite || {};
|
|
428
|
+
self._src = typeof o.src !== "string" ? o.src : [o.src];
|
|
429
|
+
self._volume = o.volume !== void 0 ? o.volume : 1;
|
|
430
|
+
self._xhr = {
|
|
431
|
+
method: o.xhr && o.xhr.method ? o.xhr.method : "GET",
|
|
432
|
+
headers: o.xhr && o.xhr.headers ? o.xhr.headers : null,
|
|
433
|
+
withCredentials: o.xhr && o.xhr.withCredentials ? o.xhr.withCredentials : false
|
|
434
|
+
};
|
|
435
|
+
self._duration = 0;
|
|
436
|
+
self._state = "unloaded";
|
|
437
|
+
self._sounds = [];
|
|
438
|
+
self._endTimers = {};
|
|
439
|
+
self._queue = [];
|
|
440
|
+
self._playLock = false;
|
|
441
|
+
self._onend = o.onend ? [{ fn: o.onend }] : [];
|
|
442
|
+
self._onfade = o.onfade ? [{ fn: o.onfade }] : [];
|
|
443
|
+
self._onload = o.onload ? [{ fn: o.onload }] : [];
|
|
444
|
+
self._onloaderror = o.onloaderror ? [{ fn: o.onloaderror }] : [];
|
|
445
|
+
self._onplayerror = o.onplayerror ? [{ fn: o.onplayerror }] : [];
|
|
446
|
+
self._onpause = o.onpause ? [{ fn: o.onpause }] : [];
|
|
447
|
+
self._onplay = o.onplay ? [{ fn: o.onplay }] : [];
|
|
448
|
+
self._onstop = o.onstop ? [{ fn: o.onstop }] : [];
|
|
449
|
+
self._onmute = o.onmute ? [{ fn: o.onmute }] : [];
|
|
450
|
+
self._onvolume = o.onvolume ? [{ fn: o.onvolume }] : [];
|
|
451
|
+
self._onrate = o.onrate ? [{ fn: o.onrate }] : [];
|
|
452
|
+
self._onseek = o.onseek ? [{ fn: o.onseek }] : [];
|
|
453
|
+
self._onunlock = o.onunlock ? [{ fn: o.onunlock }] : [];
|
|
454
|
+
self._onresume = [];
|
|
455
|
+
self._webAudio = Howler3.usingWebAudio && !self._html5;
|
|
456
|
+
if (typeof Howler3.ctx !== "undefined" && Howler3.ctx && Howler3.autoUnlock) {
|
|
457
|
+
Howler3._unlockAudio();
|
|
458
|
+
}
|
|
459
|
+
Howler3._howls.push(self);
|
|
460
|
+
if (self._autoplay) {
|
|
461
|
+
self._queue.push({
|
|
462
|
+
event: "play",
|
|
463
|
+
action: function() {
|
|
464
|
+
self.play();
|
|
465
|
+
}
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
if (self._preload && self._preload !== "none") {
|
|
469
|
+
self.load();
|
|
470
|
+
}
|
|
471
|
+
return self;
|
|
472
|
+
},
|
|
473
|
+
/**
|
|
474
|
+
* Load the audio file.
|
|
475
|
+
* @return {Howler}
|
|
476
|
+
*/
|
|
477
|
+
load: function() {
|
|
478
|
+
var self = this;
|
|
479
|
+
var url = null;
|
|
480
|
+
if (Howler3.noAudio) {
|
|
481
|
+
self._emit("loaderror", null, "No audio support.");
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
if (typeof self._src === "string") {
|
|
485
|
+
self._src = [self._src];
|
|
486
|
+
}
|
|
487
|
+
for (var i = 0; i < self._src.length; i++) {
|
|
488
|
+
var ext, str;
|
|
489
|
+
if (self._format && self._format[i]) {
|
|
490
|
+
ext = self._format[i];
|
|
491
|
+
} else {
|
|
492
|
+
str = self._src[i];
|
|
493
|
+
if (typeof str !== "string") {
|
|
494
|
+
self._emit("loaderror", null, "Non-string found in selected audio sources - ignoring.");
|
|
495
|
+
continue;
|
|
496
|
+
}
|
|
497
|
+
ext = /^data:audio\/([^;,]+);/i.exec(str);
|
|
498
|
+
if (!ext) {
|
|
499
|
+
ext = /\.([^.]+)$/.exec(str.split("?", 1)[0]);
|
|
500
|
+
}
|
|
501
|
+
if (ext) {
|
|
502
|
+
ext = ext[1].toLowerCase();
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
if (!ext) {
|
|
506
|
+
console.warn('No file extension was found. Consider using the "format" property or specify an extension.');
|
|
507
|
+
}
|
|
508
|
+
if (ext && Howler3.codecs(ext)) {
|
|
509
|
+
url = self._src[i];
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
if (!url) {
|
|
514
|
+
self._emit("loaderror", null, "No codec support for selected audio sources.");
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
self._src = url;
|
|
518
|
+
self._state = "loading";
|
|
519
|
+
if (window.location.protocol === "https:" && url.slice(0, 5) === "http:") {
|
|
520
|
+
self._html5 = true;
|
|
521
|
+
self._webAudio = false;
|
|
522
|
+
}
|
|
523
|
+
new Sound2(self);
|
|
524
|
+
if (self._webAudio) {
|
|
525
|
+
loadBuffer(self);
|
|
526
|
+
}
|
|
527
|
+
return self;
|
|
528
|
+
},
|
|
529
|
+
/**
|
|
530
|
+
* Play a sound or resume previous playback.
|
|
531
|
+
* @param {String/Number} sprite Sprite name for sprite playback or sound id to continue previous.
|
|
532
|
+
* @param {Boolean} internal Internal Use: true prevents event firing.
|
|
533
|
+
* @return {Number} Sound ID.
|
|
534
|
+
*/
|
|
535
|
+
play: function(sprite, internal) {
|
|
536
|
+
var self = this;
|
|
537
|
+
var id = null;
|
|
538
|
+
if (typeof sprite === "number") {
|
|
539
|
+
id = sprite;
|
|
540
|
+
sprite = null;
|
|
541
|
+
} else if (typeof sprite === "string" && self._state === "loaded" && !self._sprite[sprite]) {
|
|
542
|
+
return null;
|
|
543
|
+
} else if (typeof sprite === "undefined") {
|
|
544
|
+
sprite = "__default";
|
|
545
|
+
if (!self._playLock) {
|
|
546
|
+
var num = 0;
|
|
547
|
+
for (var i = 0; i < self._sounds.length; i++) {
|
|
548
|
+
if (self._sounds[i]._paused && !self._sounds[i]._ended) {
|
|
549
|
+
num++;
|
|
550
|
+
id = self._sounds[i]._id;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
if (num === 1) {
|
|
554
|
+
sprite = null;
|
|
555
|
+
} else {
|
|
556
|
+
id = null;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
var sound = id ? self._soundById(id) : self._inactiveSound();
|
|
561
|
+
if (!sound) {
|
|
562
|
+
return null;
|
|
563
|
+
}
|
|
564
|
+
if (id && !sprite) {
|
|
565
|
+
sprite = sound._sprite || "__default";
|
|
566
|
+
}
|
|
567
|
+
if (self._state !== "loaded") {
|
|
568
|
+
sound._sprite = sprite;
|
|
569
|
+
sound._ended = false;
|
|
570
|
+
var soundId = sound._id;
|
|
571
|
+
self._queue.push({
|
|
572
|
+
event: "play",
|
|
573
|
+
action: function() {
|
|
574
|
+
self.play(soundId);
|
|
575
|
+
}
|
|
576
|
+
});
|
|
577
|
+
return soundId;
|
|
578
|
+
}
|
|
579
|
+
if (id && !sound._paused) {
|
|
580
|
+
if (!internal) {
|
|
581
|
+
self._loadQueue("play");
|
|
582
|
+
}
|
|
583
|
+
return sound._id;
|
|
584
|
+
}
|
|
585
|
+
if (self._webAudio) {
|
|
586
|
+
Howler3._autoResume();
|
|
587
|
+
}
|
|
588
|
+
var seek = Math.max(0, sound._seek > 0 ? sound._seek : self._sprite[sprite][0] / 1e3);
|
|
589
|
+
var duration = Math.max(0, (self._sprite[sprite][0] + self._sprite[sprite][1]) / 1e3 - seek);
|
|
590
|
+
var timeout = duration * 1e3 / Math.abs(sound._rate);
|
|
591
|
+
var start = self._sprite[sprite][0] / 1e3;
|
|
592
|
+
var stop = (self._sprite[sprite][0] + self._sprite[sprite][1]) / 1e3;
|
|
593
|
+
sound._sprite = sprite;
|
|
594
|
+
sound._ended = false;
|
|
595
|
+
var setParams = function() {
|
|
596
|
+
sound._paused = false;
|
|
597
|
+
sound._seek = seek;
|
|
598
|
+
sound._start = start;
|
|
599
|
+
sound._stop = stop;
|
|
600
|
+
sound._loop = !!(sound._loop || self._sprite[sprite][2]);
|
|
601
|
+
};
|
|
602
|
+
if (seek >= stop) {
|
|
603
|
+
self._ended(sound);
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
var node = sound._node;
|
|
607
|
+
if (self._webAudio) {
|
|
608
|
+
var playWebAudio = function() {
|
|
609
|
+
self._playLock = false;
|
|
610
|
+
setParams();
|
|
611
|
+
self._refreshBuffer(sound);
|
|
612
|
+
var vol = sound._muted || self._muted ? 0 : sound._volume;
|
|
613
|
+
node.gain.setValueAtTime(vol, Howler3.ctx.currentTime);
|
|
614
|
+
sound._playStart = Howler3.ctx.currentTime;
|
|
615
|
+
if (typeof node.bufferSource.start === "undefined") {
|
|
616
|
+
sound._loop ? node.bufferSource.noteGrainOn(0, seek, 86400) : node.bufferSource.noteGrainOn(0, seek, duration);
|
|
617
|
+
} else {
|
|
618
|
+
sound._loop ? node.bufferSource.start(0, seek, 86400) : node.bufferSource.start(0, seek, duration);
|
|
619
|
+
}
|
|
620
|
+
if (timeout !== Infinity) {
|
|
621
|
+
self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout);
|
|
622
|
+
}
|
|
623
|
+
if (!internal) {
|
|
624
|
+
setTimeout(function() {
|
|
625
|
+
self._emit("play", sound._id);
|
|
626
|
+
self._loadQueue();
|
|
627
|
+
}, 0);
|
|
628
|
+
}
|
|
629
|
+
};
|
|
630
|
+
if (Howler3.state === "running" && Howler3.ctx.state !== "interrupted") {
|
|
631
|
+
playWebAudio();
|
|
632
|
+
} else {
|
|
633
|
+
self._playLock = true;
|
|
634
|
+
self.once("resume", playWebAudio);
|
|
635
|
+
self._clearTimer(sound._id);
|
|
636
|
+
}
|
|
637
|
+
} else {
|
|
638
|
+
var playHtml5 = function() {
|
|
639
|
+
node.currentTime = seek;
|
|
640
|
+
node.muted = sound._muted || self._muted || Howler3._muted || node.muted;
|
|
641
|
+
node.volume = sound._volume * Howler3.volume();
|
|
642
|
+
node.playbackRate = sound._rate;
|
|
643
|
+
try {
|
|
644
|
+
var play = node.play();
|
|
645
|
+
if (play && typeof Promise !== "undefined" && (play instanceof Promise || typeof play.then === "function")) {
|
|
646
|
+
self._playLock = true;
|
|
647
|
+
setParams();
|
|
648
|
+
play.then(function() {
|
|
649
|
+
self._playLock = false;
|
|
650
|
+
node._unlocked = true;
|
|
651
|
+
if (!internal) {
|
|
652
|
+
self._emit("play", sound._id);
|
|
653
|
+
} else {
|
|
654
|
+
self._loadQueue();
|
|
655
|
+
}
|
|
656
|
+
}).catch(function() {
|
|
657
|
+
self._playLock = false;
|
|
658
|
+
self._emit("playerror", sound._id, "Playback was unable to start. This is most commonly an issue on mobile devices and Chrome where playback was not within a user interaction.");
|
|
659
|
+
sound._ended = true;
|
|
660
|
+
sound._paused = true;
|
|
661
|
+
});
|
|
662
|
+
} else if (!internal) {
|
|
663
|
+
self._playLock = false;
|
|
664
|
+
setParams();
|
|
665
|
+
self._emit("play", sound._id);
|
|
666
|
+
}
|
|
667
|
+
node.playbackRate = sound._rate;
|
|
668
|
+
if (node.paused) {
|
|
669
|
+
self._emit("playerror", sound._id, "Playback was unable to start. This is most commonly an issue on mobile devices and Chrome where playback was not within a user interaction.");
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
if (sprite !== "__default" || sound._loop) {
|
|
673
|
+
self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout);
|
|
674
|
+
} else {
|
|
675
|
+
self._endTimers[sound._id] = function() {
|
|
676
|
+
self._ended(sound);
|
|
677
|
+
node.removeEventListener("ended", self._endTimers[sound._id], false);
|
|
678
|
+
};
|
|
679
|
+
node.addEventListener("ended", self._endTimers[sound._id], false);
|
|
680
|
+
}
|
|
681
|
+
} catch (err) {
|
|
682
|
+
self._emit("playerror", sound._id, err);
|
|
683
|
+
}
|
|
684
|
+
};
|
|
685
|
+
if (node.src === "data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA") {
|
|
686
|
+
node.src = self._src;
|
|
687
|
+
node.load();
|
|
688
|
+
}
|
|
689
|
+
var loadedNoReadyState = window && window.ejecta || !node.readyState && Howler3._navigator.isCocoonJS;
|
|
690
|
+
if (node.readyState >= 3 || loadedNoReadyState) {
|
|
691
|
+
playHtml5();
|
|
692
|
+
} else {
|
|
693
|
+
self._playLock = true;
|
|
694
|
+
self._state = "loading";
|
|
695
|
+
var listener = function() {
|
|
696
|
+
self._state = "loaded";
|
|
697
|
+
playHtml5();
|
|
698
|
+
node.removeEventListener(Howler3._canPlayEvent, listener, false);
|
|
699
|
+
};
|
|
700
|
+
node.addEventListener(Howler3._canPlayEvent, listener, false);
|
|
701
|
+
self._clearTimer(sound._id);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
return sound._id;
|
|
705
|
+
},
|
|
706
|
+
/**
|
|
707
|
+
* Pause playback and save current position.
|
|
708
|
+
* @param {Number} id The sound ID (empty to pause all in group).
|
|
709
|
+
* @return {Howl}
|
|
710
|
+
*/
|
|
711
|
+
pause: function(id) {
|
|
712
|
+
var self = this;
|
|
713
|
+
if (self._state !== "loaded" || self._playLock) {
|
|
714
|
+
self._queue.push({
|
|
715
|
+
event: "pause",
|
|
716
|
+
action: function() {
|
|
717
|
+
self.pause(id);
|
|
718
|
+
}
|
|
719
|
+
});
|
|
720
|
+
return self;
|
|
721
|
+
}
|
|
722
|
+
var ids = self._getSoundIds(id);
|
|
723
|
+
for (var i = 0; i < ids.length; i++) {
|
|
724
|
+
self._clearTimer(ids[i]);
|
|
725
|
+
var sound = self._soundById(ids[i]);
|
|
726
|
+
if (sound && !sound._paused) {
|
|
727
|
+
sound._seek = self.seek(ids[i]);
|
|
728
|
+
sound._rateSeek = 0;
|
|
729
|
+
sound._paused = true;
|
|
730
|
+
self._stopFade(ids[i]);
|
|
731
|
+
if (sound._node) {
|
|
732
|
+
if (self._webAudio) {
|
|
733
|
+
if (!sound._node.bufferSource) {
|
|
734
|
+
continue;
|
|
735
|
+
}
|
|
736
|
+
if (typeof sound._node.bufferSource.stop === "undefined") {
|
|
737
|
+
sound._node.bufferSource.noteOff(0);
|
|
738
|
+
} else {
|
|
739
|
+
sound._node.bufferSource.stop(0);
|
|
740
|
+
}
|
|
741
|
+
self._cleanBuffer(sound._node);
|
|
742
|
+
} else if (!isNaN(sound._node.duration) || sound._node.duration === Infinity) {
|
|
743
|
+
sound._node.pause();
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
if (!arguments[1]) {
|
|
748
|
+
self._emit("pause", sound ? sound._id : null);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
return self;
|
|
752
|
+
},
|
|
753
|
+
/**
|
|
754
|
+
* Stop playback and reset to start.
|
|
755
|
+
* @param {Number} id The sound ID (empty to stop all in group).
|
|
756
|
+
* @param {Boolean} internal Internal Use: true prevents event firing.
|
|
757
|
+
* @return {Howl}
|
|
758
|
+
*/
|
|
759
|
+
stop: function(id, internal) {
|
|
760
|
+
var self = this;
|
|
761
|
+
if (self._state !== "loaded" || self._playLock) {
|
|
762
|
+
self._queue.push({
|
|
763
|
+
event: "stop",
|
|
764
|
+
action: function() {
|
|
765
|
+
self.stop(id);
|
|
766
|
+
}
|
|
767
|
+
});
|
|
768
|
+
return self;
|
|
769
|
+
}
|
|
770
|
+
var ids = self._getSoundIds(id);
|
|
771
|
+
for (var i = 0; i < ids.length; i++) {
|
|
772
|
+
self._clearTimer(ids[i]);
|
|
773
|
+
var sound = self._soundById(ids[i]);
|
|
774
|
+
if (sound) {
|
|
775
|
+
sound._seek = sound._start || 0;
|
|
776
|
+
sound._rateSeek = 0;
|
|
777
|
+
sound._paused = true;
|
|
778
|
+
sound._ended = true;
|
|
779
|
+
self._stopFade(ids[i]);
|
|
780
|
+
if (sound._node) {
|
|
781
|
+
if (self._webAudio) {
|
|
782
|
+
if (sound._node.bufferSource) {
|
|
783
|
+
if (typeof sound._node.bufferSource.stop === "undefined") {
|
|
784
|
+
sound._node.bufferSource.noteOff(0);
|
|
785
|
+
} else {
|
|
786
|
+
sound._node.bufferSource.stop(0);
|
|
787
|
+
}
|
|
788
|
+
self._cleanBuffer(sound._node);
|
|
789
|
+
}
|
|
790
|
+
} else if (!isNaN(sound._node.duration) || sound._node.duration === Infinity) {
|
|
791
|
+
sound._node.currentTime = sound._start || 0;
|
|
792
|
+
sound._node.pause();
|
|
793
|
+
if (sound._node.duration === Infinity) {
|
|
794
|
+
self._clearSound(sound._node);
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
if (!internal) {
|
|
799
|
+
self._emit("stop", sound._id);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
return self;
|
|
804
|
+
},
|
|
805
|
+
/**
|
|
806
|
+
* Mute/unmute a single sound or all sounds in this Howl group.
|
|
807
|
+
* @param {Boolean} muted Set to true to mute and false to unmute.
|
|
808
|
+
* @param {Number} id The sound ID to update (omit to mute/unmute all).
|
|
809
|
+
* @return {Howl}
|
|
810
|
+
*/
|
|
811
|
+
mute: function(muted, id) {
|
|
812
|
+
var self = this;
|
|
813
|
+
if (self._state !== "loaded" || self._playLock) {
|
|
814
|
+
self._queue.push({
|
|
815
|
+
event: "mute",
|
|
816
|
+
action: function() {
|
|
817
|
+
self.mute(muted, id);
|
|
818
|
+
}
|
|
819
|
+
});
|
|
820
|
+
return self;
|
|
821
|
+
}
|
|
822
|
+
if (typeof id === "undefined") {
|
|
823
|
+
if (typeof muted === "boolean") {
|
|
824
|
+
self._muted = muted;
|
|
825
|
+
} else {
|
|
826
|
+
return self._muted;
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
var ids = self._getSoundIds(id);
|
|
830
|
+
for (var i = 0; i < ids.length; i++) {
|
|
831
|
+
var sound = self._soundById(ids[i]);
|
|
832
|
+
if (sound) {
|
|
833
|
+
sound._muted = muted;
|
|
834
|
+
if (sound._interval) {
|
|
835
|
+
self._stopFade(sound._id);
|
|
836
|
+
}
|
|
837
|
+
if (self._webAudio && sound._node) {
|
|
838
|
+
sound._node.gain.setValueAtTime(muted ? 0 : sound._volume, Howler3.ctx.currentTime);
|
|
839
|
+
} else if (sound._node) {
|
|
840
|
+
sound._node.muted = Howler3._muted ? true : muted;
|
|
841
|
+
}
|
|
842
|
+
self._emit("mute", sound._id);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
return self;
|
|
846
|
+
},
|
|
847
|
+
/**
|
|
848
|
+
* Get/set the volume of this sound or of the Howl group. This method can optionally take 0, 1 or 2 arguments.
|
|
849
|
+
* volume() -> Returns the group's volume value.
|
|
850
|
+
* volume(id) -> Returns the sound id's current volume.
|
|
851
|
+
* volume(vol) -> Sets the volume of all sounds in this Howl group.
|
|
852
|
+
* volume(vol, id) -> Sets the volume of passed sound id.
|
|
853
|
+
* @return {Howl/Number} Returns self or current volume.
|
|
854
|
+
*/
|
|
855
|
+
volume: function() {
|
|
856
|
+
var self = this;
|
|
857
|
+
var args = arguments;
|
|
858
|
+
var vol, id;
|
|
859
|
+
if (args.length === 0) {
|
|
860
|
+
return self._volume;
|
|
861
|
+
} else if (args.length === 1 || args.length === 2 && typeof args[1] === "undefined") {
|
|
862
|
+
var ids = self._getSoundIds();
|
|
863
|
+
var index = ids.indexOf(args[0]);
|
|
864
|
+
if (index >= 0) {
|
|
865
|
+
id = parseInt(args[0], 10);
|
|
866
|
+
} else {
|
|
867
|
+
vol = parseFloat(args[0]);
|
|
868
|
+
}
|
|
869
|
+
} else if (args.length >= 2) {
|
|
870
|
+
vol = parseFloat(args[0]);
|
|
871
|
+
id = parseInt(args[1], 10);
|
|
872
|
+
}
|
|
873
|
+
var sound;
|
|
874
|
+
if (typeof vol !== "undefined" && vol >= 0 && vol <= 1) {
|
|
875
|
+
if (self._state !== "loaded" || self._playLock) {
|
|
876
|
+
self._queue.push({
|
|
877
|
+
event: "volume",
|
|
878
|
+
action: function() {
|
|
879
|
+
self.volume.apply(self, args);
|
|
880
|
+
}
|
|
881
|
+
});
|
|
882
|
+
return self;
|
|
883
|
+
}
|
|
884
|
+
if (typeof id === "undefined") {
|
|
885
|
+
self._volume = vol;
|
|
886
|
+
}
|
|
887
|
+
id = self._getSoundIds(id);
|
|
888
|
+
for (var i = 0; i < id.length; i++) {
|
|
889
|
+
sound = self._soundById(id[i]);
|
|
890
|
+
if (sound) {
|
|
891
|
+
sound._volume = vol;
|
|
892
|
+
if (!args[2]) {
|
|
893
|
+
self._stopFade(id[i]);
|
|
894
|
+
}
|
|
895
|
+
if (self._webAudio && sound._node && !sound._muted) {
|
|
896
|
+
sound._node.gain.setValueAtTime(vol, Howler3.ctx.currentTime);
|
|
897
|
+
} else if (sound._node && !sound._muted) {
|
|
898
|
+
sound._node.volume = vol * Howler3.volume();
|
|
899
|
+
}
|
|
900
|
+
self._emit("volume", sound._id);
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
} else {
|
|
904
|
+
sound = id ? self._soundById(id) : self._sounds[0];
|
|
905
|
+
return sound ? sound._volume : 0;
|
|
906
|
+
}
|
|
907
|
+
return self;
|
|
908
|
+
},
|
|
909
|
+
/**
|
|
910
|
+
* Fade a currently playing sound between two volumes (if no id is passed, all sounds will fade).
|
|
911
|
+
* @param {Number} from The value to fade from (0.0 to 1.0).
|
|
912
|
+
* @param {Number} to The volume to fade to (0.0 to 1.0).
|
|
913
|
+
* @param {Number} len Time in milliseconds to fade.
|
|
914
|
+
* @param {Number} id The sound id (omit to fade all sounds).
|
|
915
|
+
* @return {Howl}
|
|
916
|
+
*/
|
|
917
|
+
fade: function(from, to, len, id) {
|
|
918
|
+
var self = this;
|
|
919
|
+
if (self._state !== "loaded" || self._playLock) {
|
|
920
|
+
self._queue.push({
|
|
921
|
+
event: "fade",
|
|
922
|
+
action: function() {
|
|
923
|
+
self.fade(from, to, len, id);
|
|
924
|
+
}
|
|
925
|
+
});
|
|
926
|
+
return self;
|
|
927
|
+
}
|
|
928
|
+
from = Math.min(Math.max(0, parseFloat(from)), 1);
|
|
929
|
+
to = Math.min(Math.max(0, parseFloat(to)), 1);
|
|
930
|
+
len = parseFloat(len);
|
|
931
|
+
self.volume(from, id);
|
|
932
|
+
var ids = self._getSoundIds(id);
|
|
933
|
+
for (var i = 0; i < ids.length; i++) {
|
|
934
|
+
var sound = self._soundById(ids[i]);
|
|
935
|
+
if (sound) {
|
|
936
|
+
if (!id) {
|
|
937
|
+
self._stopFade(ids[i]);
|
|
938
|
+
}
|
|
939
|
+
if (self._webAudio && !sound._muted) {
|
|
940
|
+
var currentTime = Howler3.ctx.currentTime;
|
|
941
|
+
var end = currentTime + len / 1e3;
|
|
942
|
+
sound._volume = from;
|
|
943
|
+
sound._node.gain.setValueAtTime(from, currentTime);
|
|
944
|
+
sound._node.gain.linearRampToValueAtTime(to, end);
|
|
945
|
+
}
|
|
946
|
+
self._startFadeInterval(sound, from, to, len, ids[i], typeof id === "undefined");
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
return self;
|
|
950
|
+
},
|
|
951
|
+
/**
|
|
952
|
+
* Starts the internal interval to fade a sound.
|
|
953
|
+
* @param {Object} sound Reference to sound to fade.
|
|
954
|
+
* @param {Number} from The value to fade from (0.0 to 1.0).
|
|
955
|
+
* @param {Number} to The volume to fade to (0.0 to 1.0).
|
|
956
|
+
* @param {Number} len Time in milliseconds to fade.
|
|
957
|
+
* @param {Number} id The sound id to fade.
|
|
958
|
+
* @param {Boolean} isGroup If true, set the volume on the group.
|
|
959
|
+
*/
|
|
960
|
+
_startFadeInterval: function(sound, from, to, len, id, isGroup) {
|
|
961
|
+
var self = this;
|
|
962
|
+
var vol = from;
|
|
963
|
+
var diff = to - from;
|
|
964
|
+
var steps = Math.abs(diff / 0.01);
|
|
965
|
+
var stepLen = Math.max(4, steps > 0 ? len / steps : len);
|
|
966
|
+
var lastTick = Date.now();
|
|
967
|
+
sound._fadeTo = to;
|
|
968
|
+
sound._interval = setInterval(function() {
|
|
969
|
+
var tick = (Date.now() - lastTick) / len;
|
|
970
|
+
lastTick = Date.now();
|
|
971
|
+
vol += diff * tick;
|
|
972
|
+
vol = Math.round(vol * 100) / 100;
|
|
973
|
+
if (diff < 0) {
|
|
974
|
+
vol = Math.max(to, vol);
|
|
975
|
+
} else {
|
|
976
|
+
vol = Math.min(to, vol);
|
|
977
|
+
}
|
|
978
|
+
if (self._webAudio) {
|
|
979
|
+
sound._volume = vol;
|
|
980
|
+
} else {
|
|
981
|
+
self.volume(vol, sound._id, true);
|
|
982
|
+
}
|
|
983
|
+
if (isGroup) {
|
|
984
|
+
self._volume = vol;
|
|
985
|
+
}
|
|
986
|
+
if (to < from && vol <= to || to > from && vol >= to) {
|
|
987
|
+
clearInterval(sound._interval);
|
|
988
|
+
sound._interval = null;
|
|
989
|
+
sound._fadeTo = null;
|
|
990
|
+
self.volume(to, sound._id);
|
|
991
|
+
self._emit("fade", sound._id);
|
|
992
|
+
}
|
|
993
|
+
}, stepLen);
|
|
994
|
+
},
|
|
995
|
+
/**
|
|
996
|
+
* Internal method that stops the currently playing fade when
|
|
997
|
+
* a new fade starts, volume is changed or the sound is stopped.
|
|
998
|
+
* @param {Number} id The sound id.
|
|
999
|
+
* @return {Howl}
|
|
1000
|
+
*/
|
|
1001
|
+
_stopFade: function(id) {
|
|
1002
|
+
var self = this;
|
|
1003
|
+
var sound = self._soundById(id);
|
|
1004
|
+
if (sound && sound._interval) {
|
|
1005
|
+
if (self._webAudio) {
|
|
1006
|
+
sound._node.gain.cancelScheduledValues(Howler3.ctx.currentTime);
|
|
1007
|
+
}
|
|
1008
|
+
clearInterval(sound._interval);
|
|
1009
|
+
sound._interval = null;
|
|
1010
|
+
self.volume(sound._fadeTo, id);
|
|
1011
|
+
sound._fadeTo = null;
|
|
1012
|
+
self._emit("fade", id);
|
|
1013
|
+
}
|
|
1014
|
+
return self;
|
|
1015
|
+
},
|
|
1016
|
+
/**
|
|
1017
|
+
* Get/set the loop parameter on a sound. This method can optionally take 0, 1 or 2 arguments.
|
|
1018
|
+
* loop() -> Returns the group's loop value.
|
|
1019
|
+
* loop(id) -> Returns the sound id's loop value.
|
|
1020
|
+
* loop(loop) -> Sets the loop value for all sounds in this Howl group.
|
|
1021
|
+
* loop(loop, id) -> Sets the loop value of passed sound id.
|
|
1022
|
+
* @return {Howl/Boolean} Returns self or current loop value.
|
|
1023
|
+
*/
|
|
1024
|
+
loop: function() {
|
|
1025
|
+
var self = this;
|
|
1026
|
+
var args = arguments;
|
|
1027
|
+
var loop, id, sound;
|
|
1028
|
+
if (args.length === 0) {
|
|
1029
|
+
return self._loop;
|
|
1030
|
+
} else if (args.length === 1) {
|
|
1031
|
+
if (typeof args[0] === "boolean") {
|
|
1032
|
+
loop = args[0];
|
|
1033
|
+
self._loop = loop;
|
|
1034
|
+
} else {
|
|
1035
|
+
sound = self._soundById(parseInt(args[0], 10));
|
|
1036
|
+
return sound ? sound._loop : false;
|
|
1037
|
+
}
|
|
1038
|
+
} else if (args.length === 2) {
|
|
1039
|
+
loop = args[0];
|
|
1040
|
+
id = parseInt(args[1], 10);
|
|
1041
|
+
}
|
|
1042
|
+
var ids = self._getSoundIds(id);
|
|
1043
|
+
for (var i = 0; i < ids.length; i++) {
|
|
1044
|
+
sound = self._soundById(ids[i]);
|
|
1045
|
+
if (sound) {
|
|
1046
|
+
sound._loop = loop;
|
|
1047
|
+
if (self._webAudio && sound._node && sound._node.bufferSource) {
|
|
1048
|
+
sound._node.bufferSource.loop = loop;
|
|
1049
|
+
if (loop) {
|
|
1050
|
+
sound._node.bufferSource.loopStart = sound._start || 0;
|
|
1051
|
+
sound._node.bufferSource.loopEnd = sound._stop;
|
|
1052
|
+
if (self.playing(ids[i])) {
|
|
1053
|
+
self.pause(ids[i], true);
|
|
1054
|
+
self.play(ids[i], true);
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
return self;
|
|
1061
|
+
},
|
|
1062
|
+
/**
|
|
1063
|
+
* Get/set the playback rate of a sound. This method can optionally take 0, 1 or 2 arguments.
|
|
1064
|
+
* rate() -> Returns the first sound node's current playback rate.
|
|
1065
|
+
* rate(id) -> Returns the sound id's current playback rate.
|
|
1066
|
+
* rate(rate) -> Sets the playback rate of all sounds in this Howl group.
|
|
1067
|
+
* rate(rate, id) -> Sets the playback rate of passed sound id.
|
|
1068
|
+
* @return {Howl/Number} Returns self or the current playback rate.
|
|
1069
|
+
*/
|
|
1070
|
+
rate: function() {
|
|
1071
|
+
var self = this;
|
|
1072
|
+
var args = arguments;
|
|
1073
|
+
var rate, id;
|
|
1074
|
+
if (args.length === 0) {
|
|
1075
|
+
id = self._sounds[0]._id;
|
|
1076
|
+
} else if (args.length === 1) {
|
|
1077
|
+
var ids = self._getSoundIds();
|
|
1078
|
+
var index = ids.indexOf(args[0]);
|
|
1079
|
+
if (index >= 0) {
|
|
1080
|
+
id = parseInt(args[0], 10);
|
|
1081
|
+
} else {
|
|
1082
|
+
rate = parseFloat(args[0]);
|
|
1083
|
+
}
|
|
1084
|
+
} else if (args.length === 2) {
|
|
1085
|
+
rate = parseFloat(args[0]);
|
|
1086
|
+
id = parseInt(args[1], 10);
|
|
1087
|
+
}
|
|
1088
|
+
var sound;
|
|
1089
|
+
if (typeof rate === "number") {
|
|
1090
|
+
if (self._state !== "loaded" || self._playLock) {
|
|
1091
|
+
self._queue.push({
|
|
1092
|
+
event: "rate",
|
|
1093
|
+
action: function() {
|
|
1094
|
+
self.rate.apply(self, args);
|
|
1095
|
+
}
|
|
1096
|
+
});
|
|
1097
|
+
return self;
|
|
1098
|
+
}
|
|
1099
|
+
if (typeof id === "undefined") {
|
|
1100
|
+
self._rate = rate;
|
|
1101
|
+
}
|
|
1102
|
+
id = self._getSoundIds(id);
|
|
1103
|
+
for (var i = 0; i < id.length; i++) {
|
|
1104
|
+
sound = self._soundById(id[i]);
|
|
1105
|
+
if (sound) {
|
|
1106
|
+
if (self.playing(id[i])) {
|
|
1107
|
+
sound._rateSeek = self.seek(id[i]);
|
|
1108
|
+
sound._playStart = self._webAudio ? Howler3.ctx.currentTime : sound._playStart;
|
|
1109
|
+
}
|
|
1110
|
+
sound._rate = rate;
|
|
1111
|
+
if (self._webAudio && sound._node && sound._node.bufferSource) {
|
|
1112
|
+
sound._node.bufferSource.playbackRate.setValueAtTime(rate, Howler3.ctx.currentTime);
|
|
1113
|
+
} else if (sound._node) {
|
|
1114
|
+
sound._node.playbackRate = rate;
|
|
1115
|
+
}
|
|
1116
|
+
var seek = self.seek(id[i]);
|
|
1117
|
+
var duration = (self._sprite[sound._sprite][0] + self._sprite[sound._sprite][1]) / 1e3 - seek;
|
|
1118
|
+
var timeout = duration * 1e3 / Math.abs(sound._rate);
|
|
1119
|
+
if (self._endTimers[id[i]] || !sound._paused) {
|
|
1120
|
+
self._clearTimer(id[i]);
|
|
1121
|
+
self._endTimers[id[i]] = setTimeout(self._ended.bind(self, sound), timeout);
|
|
1122
|
+
}
|
|
1123
|
+
self._emit("rate", sound._id);
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
} else {
|
|
1127
|
+
sound = self._soundById(id);
|
|
1128
|
+
return sound ? sound._rate : self._rate;
|
|
1129
|
+
}
|
|
1130
|
+
return self;
|
|
1131
|
+
},
|
|
1132
|
+
/**
|
|
1133
|
+
* Get/set the seek position of a sound. This method can optionally take 0, 1 or 2 arguments.
|
|
1134
|
+
* seek() -> Returns the first sound node's current seek position.
|
|
1135
|
+
* seek(id) -> Returns the sound id's current seek position.
|
|
1136
|
+
* seek(seek) -> Sets the seek position of the first sound node.
|
|
1137
|
+
* seek(seek, id) -> Sets the seek position of passed sound id.
|
|
1138
|
+
* @return {Howl/Number} Returns self or the current seek position.
|
|
1139
|
+
*/
|
|
1140
|
+
seek: function() {
|
|
1141
|
+
var self = this;
|
|
1142
|
+
var args = arguments;
|
|
1143
|
+
var seek, id;
|
|
1144
|
+
if (args.length === 0) {
|
|
1145
|
+
if (self._sounds.length) {
|
|
1146
|
+
id = self._sounds[0]._id;
|
|
1147
|
+
}
|
|
1148
|
+
} else if (args.length === 1) {
|
|
1149
|
+
var ids = self._getSoundIds();
|
|
1150
|
+
var index = ids.indexOf(args[0]);
|
|
1151
|
+
if (index >= 0) {
|
|
1152
|
+
id = parseInt(args[0], 10);
|
|
1153
|
+
} else if (self._sounds.length) {
|
|
1154
|
+
id = self._sounds[0]._id;
|
|
1155
|
+
seek = parseFloat(args[0]);
|
|
1156
|
+
}
|
|
1157
|
+
} else if (args.length === 2) {
|
|
1158
|
+
seek = parseFloat(args[0]);
|
|
1159
|
+
id = parseInt(args[1], 10);
|
|
1160
|
+
}
|
|
1161
|
+
if (typeof id === "undefined") {
|
|
1162
|
+
return 0;
|
|
1163
|
+
}
|
|
1164
|
+
if (typeof seek === "number" && (self._state !== "loaded" || self._playLock)) {
|
|
1165
|
+
self._queue.push({
|
|
1166
|
+
event: "seek",
|
|
1167
|
+
action: function() {
|
|
1168
|
+
self.seek.apply(self, args);
|
|
1169
|
+
}
|
|
1170
|
+
});
|
|
1171
|
+
return self;
|
|
1172
|
+
}
|
|
1173
|
+
var sound = self._soundById(id);
|
|
1174
|
+
if (sound) {
|
|
1175
|
+
if (typeof seek === "number" && seek >= 0) {
|
|
1176
|
+
var playing = self.playing(id);
|
|
1177
|
+
if (playing) {
|
|
1178
|
+
self.pause(id, true);
|
|
1179
|
+
}
|
|
1180
|
+
sound._seek = seek;
|
|
1181
|
+
sound._ended = false;
|
|
1182
|
+
self._clearTimer(id);
|
|
1183
|
+
if (!self._webAudio && sound._node && !isNaN(sound._node.duration)) {
|
|
1184
|
+
sound._node.currentTime = seek;
|
|
1185
|
+
}
|
|
1186
|
+
var seekAndEmit = function() {
|
|
1187
|
+
if (playing) {
|
|
1188
|
+
self.play(id, true);
|
|
1189
|
+
}
|
|
1190
|
+
self._emit("seek", id);
|
|
1191
|
+
};
|
|
1192
|
+
if (playing && !self._webAudio) {
|
|
1193
|
+
var emitSeek = function() {
|
|
1194
|
+
if (!self._playLock) {
|
|
1195
|
+
seekAndEmit();
|
|
1196
|
+
} else {
|
|
1197
|
+
setTimeout(emitSeek, 0);
|
|
1198
|
+
}
|
|
1199
|
+
};
|
|
1200
|
+
setTimeout(emitSeek, 0);
|
|
1201
|
+
} else {
|
|
1202
|
+
seekAndEmit();
|
|
1203
|
+
}
|
|
1204
|
+
} else {
|
|
1205
|
+
if (self._webAudio) {
|
|
1206
|
+
var realTime = self.playing(id) ? Howler3.ctx.currentTime - sound._playStart : 0;
|
|
1207
|
+
var rateSeek = sound._rateSeek ? sound._rateSeek - sound._seek : 0;
|
|
1208
|
+
return sound._seek + (rateSeek + realTime * Math.abs(sound._rate));
|
|
1209
|
+
} else {
|
|
1210
|
+
return sound._node.currentTime;
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
return self;
|
|
1215
|
+
},
|
|
1216
|
+
/**
|
|
1217
|
+
* Check if a specific sound is currently playing or not (if id is provided), or check if at least one of the sounds in the group is playing or not.
|
|
1218
|
+
* @param {Number} id The sound id to check. If none is passed, the whole sound group is checked.
|
|
1219
|
+
* @return {Boolean} True if playing and false if not.
|
|
1220
|
+
*/
|
|
1221
|
+
playing: function(id) {
|
|
1222
|
+
var self = this;
|
|
1223
|
+
if (typeof id === "number") {
|
|
1224
|
+
var sound = self._soundById(id);
|
|
1225
|
+
return sound ? !sound._paused : false;
|
|
1226
|
+
}
|
|
1227
|
+
for (var i = 0; i < self._sounds.length; i++) {
|
|
1228
|
+
if (!self._sounds[i]._paused) {
|
|
1229
|
+
return true;
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
return false;
|
|
1233
|
+
},
|
|
1234
|
+
/**
|
|
1235
|
+
* Get the duration of this sound. Passing a sound id will return the sprite duration.
|
|
1236
|
+
* @param {Number} id The sound id to check. If none is passed, return full source duration.
|
|
1237
|
+
* @return {Number} Audio duration in seconds.
|
|
1238
|
+
*/
|
|
1239
|
+
duration: function(id) {
|
|
1240
|
+
var self = this;
|
|
1241
|
+
var duration = self._duration;
|
|
1242
|
+
var sound = self._soundById(id);
|
|
1243
|
+
if (sound) {
|
|
1244
|
+
duration = self._sprite[sound._sprite][1] / 1e3;
|
|
1245
|
+
}
|
|
1246
|
+
return duration;
|
|
1247
|
+
},
|
|
1248
|
+
/**
|
|
1249
|
+
* Returns the current loaded state of this Howl.
|
|
1250
|
+
* @return {String} 'unloaded', 'loading', 'loaded'
|
|
1251
|
+
*/
|
|
1252
|
+
state: function() {
|
|
1253
|
+
return this._state;
|
|
1254
|
+
},
|
|
1255
|
+
/**
|
|
1256
|
+
* Unload and destroy the current Howl object.
|
|
1257
|
+
* This will immediately stop all sound instances attached to this group.
|
|
1258
|
+
*/
|
|
1259
|
+
unload: function() {
|
|
1260
|
+
var self = this;
|
|
1261
|
+
var sounds = self._sounds;
|
|
1262
|
+
for (var i = 0; i < sounds.length; i++) {
|
|
1263
|
+
if (!sounds[i]._paused) {
|
|
1264
|
+
self.stop(sounds[i]._id);
|
|
1265
|
+
}
|
|
1266
|
+
if (!self._webAudio) {
|
|
1267
|
+
self._clearSound(sounds[i]._node);
|
|
1268
|
+
sounds[i]._node.removeEventListener("error", sounds[i]._errorFn, false);
|
|
1269
|
+
sounds[i]._node.removeEventListener(Howler3._canPlayEvent, sounds[i]._loadFn, false);
|
|
1270
|
+
sounds[i]._node.removeEventListener("ended", sounds[i]._endFn, false);
|
|
1271
|
+
Howler3._releaseHtml5Audio(sounds[i]._node);
|
|
1272
|
+
}
|
|
1273
|
+
delete sounds[i]._node;
|
|
1274
|
+
self._clearTimer(sounds[i]._id);
|
|
1275
|
+
}
|
|
1276
|
+
var index = Howler3._howls.indexOf(self);
|
|
1277
|
+
if (index >= 0) {
|
|
1278
|
+
Howler3._howls.splice(index, 1);
|
|
1279
|
+
}
|
|
1280
|
+
var remCache = true;
|
|
1281
|
+
for (i = 0; i < Howler3._howls.length; i++) {
|
|
1282
|
+
if (Howler3._howls[i]._src === self._src || self._src.indexOf(Howler3._howls[i]._src) >= 0) {
|
|
1283
|
+
remCache = false;
|
|
1284
|
+
break;
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
if (cache && remCache) {
|
|
1288
|
+
delete cache[self._src];
|
|
1289
|
+
}
|
|
1290
|
+
Howler3.noAudio = false;
|
|
1291
|
+
self._state = "unloaded";
|
|
1292
|
+
self._sounds = [];
|
|
1293
|
+
self = null;
|
|
1294
|
+
return null;
|
|
1295
|
+
},
|
|
1296
|
+
/**
|
|
1297
|
+
* Listen to a custom event.
|
|
1298
|
+
* @param {String} event Event name.
|
|
1299
|
+
* @param {Function} fn Listener to call.
|
|
1300
|
+
* @param {Number} id (optional) Only listen to events for this sound.
|
|
1301
|
+
* @param {Number} once (INTERNAL) Marks event to fire only once.
|
|
1302
|
+
* @return {Howl}
|
|
1303
|
+
*/
|
|
1304
|
+
on: function(event, fn, id, once) {
|
|
1305
|
+
var self = this;
|
|
1306
|
+
var events = self["_on" + event];
|
|
1307
|
+
if (typeof fn === "function") {
|
|
1308
|
+
events.push(once ? { id, fn, once } : { id, fn });
|
|
1309
|
+
}
|
|
1310
|
+
return self;
|
|
1311
|
+
},
|
|
1312
|
+
/**
|
|
1313
|
+
* Remove a custom event. Call without parameters to remove all events.
|
|
1314
|
+
* @param {String} event Event name.
|
|
1315
|
+
* @param {Function} fn Listener to remove. Leave empty to remove all.
|
|
1316
|
+
* @param {Number} id (optional) Only remove events for this sound.
|
|
1317
|
+
* @return {Howl}
|
|
1318
|
+
*/
|
|
1319
|
+
off: function(event, fn, id) {
|
|
1320
|
+
var self = this;
|
|
1321
|
+
var events = self["_on" + event];
|
|
1322
|
+
var i = 0;
|
|
1323
|
+
if (typeof fn === "number") {
|
|
1324
|
+
id = fn;
|
|
1325
|
+
fn = null;
|
|
1326
|
+
}
|
|
1327
|
+
if (fn || id) {
|
|
1328
|
+
for (i = 0; i < events.length; i++) {
|
|
1329
|
+
var isId = id === events[i].id;
|
|
1330
|
+
if (fn === events[i].fn && isId || !fn && isId) {
|
|
1331
|
+
events.splice(i, 1);
|
|
1332
|
+
break;
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
} else if (event) {
|
|
1336
|
+
self["_on" + event] = [];
|
|
1337
|
+
} else {
|
|
1338
|
+
var keys = Object.keys(self);
|
|
1339
|
+
for (i = 0; i < keys.length; i++) {
|
|
1340
|
+
if (keys[i].indexOf("_on") === 0 && Array.isArray(self[keys[i]])) {
|
|
1341
|
+
self[keys[i]] = [];
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
return self;
|
|
1346
|
+
},
|
|
1347
|
+
/**
|
|
1348
|
+
* Listen to a custom event and remove it once fired.
|
|
1349
|
+
* @param {String} event Event name.
|
|
1350
|
+
* @param {Function} fn Listener to call.
|
|
1351
|
+
* @param {Number} id (optional) Only listen to events for this sound.
|
|
1352
|
+
* @return {Howl}
|
|
1353
|
+
*/
|
|
1354
|
+
once: function(event, fn, id) {
|
|
1355
|
+
var self = this;
|
|
1356
|
+
self.on(event, fn, id, 1);
|
|
1357
|
+
return self;
|
|
1358
|
+
},
|
|
1359
|
+
/**
|
|
1360
|
+
* Emit all events of a specific type and pass the sound id.
|
|
1361
|
+
* @param {String} event Event name.
|
|
1362
|
+
* @param {Number} id Sound ID.
|
|
1363
|
+
* @param {Number} msg Message to go with event.
|
|
1364
|
+
* @return {Howl}
|
|
1365
|
+
*/
|
|
1366
|
+
_emit: function(event, id, msg) {
|
|
1367
|
+
var self = this;
|
|
1368
|
+
var events = self["_on" + event];
|
|
1369
|
+
for (var i = events.length - 1; i >= 0; i--) {
|
|
1370
|
+
if (!events[i].id || events[i].id === id || event === "load") {
|
|
1371
|
+
setTimeout(function(fn) {
|
|
1372
|
+
fn.call(this, id, msg);
|
|
1373
|
+
}.bind(self, events[i].fn), 0);
|
|
1374
|
+
if (events[i].once) {
|
|
1375
|
+
self.off(event, events[i].fn, events[i].id);
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
self._loadQueue(event);
|
|
1380
|
+
return self;
|
|
1381
|
+
},
|
|
1382
|
+
/**
|
|
1383
|
+
* Queue of actions initiated before the sound has loaded.
|
|
1384
|
+
* These will be called in sequence, with the next only firing
|
|
1385
|
+
* after the previous has finished executing (even if async like play).
|
|
1386
|
+
* @return {Howl}
|
|
1387
|
+
*/
|
|
1388
|
+
_loadQueue: function(event) {
|
|
1389
|
+
var self = this;
|
|
1390
|
+
if (self._queue.length > 0) {
|
|
1391
|
+
var task = self._queue[0];
|
|
1392
|
+
if (task.event === event) {
|
|
1393
|
+
self._queue.shift();
|
|
1394
|
+
self._loadQueue();
|
|
1395
|
+
}
|
|
1396
|
+
if (!event) {
|
|
1397
|
+
task.action();
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
return self;
|
|
1401
|
+
},
|
|
1402
|
+
/**
|
|
1403
|
+
* Fired when playback ends at the end of the duration.
|
|
1404
|
+
* @param {Sound} sound The sound object to work with.
|
|
1405
|
+
* @return {Howl}
|
|
1406
|
+
*/
|
|
1407
|
+
_ended: function(sound) {
|
|
1408
|
+
var self = this;
|
|
1409
|
+
var sprite = sound._sprite;
|
|
1410
|
+
if (!self._webAudio && sound._node && !sound._node.paused && !sound._node.ended && sound._node.currentTime < sound._stop) {
|
|
1411
|
+
setTimeout(self._ended.bind(self, sound), 100);
|
|
1412
|
+
return self;
|
|
1413
|
+
}
|
|
1414
|
+
var loop = !!(sound._loop || self._sprite[sprite][2]);
|
|
1415
|
+
self._emit("end", sound._id);
|
|
1416
|
+
if (!self._webAudio && loop) {
|
|
1417
|
+
self.stop(sound._id, true).play(sound._id);
|
|
1418
|
+
}
|
|
1419
|
+
if (self._webAudio && loop) {
|
|
1420
|
+
self._emit("play", sound._id);
|
|
1421
|
+
sound._seek = sound._start || 0;
|
|
1422
|
+
sound._rateSeek = 0;
|
|
1423
|
+
sound._playStart = Howler3.ctx.currentTime;
|
|
1424
|
+
var timeout = (sound._stop - sound._start) * 1e3 / Math.abs(sound._rate);
|
|
1425
|
+
self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout);
|
|
1426
|
+
}
|
|
1427
|
+
if (self._webAudio && !loop) {
|
|
1428
|
+
sound._paused = true;
|
|
1429
|
+
sound._ended = true;
|
|
1430
|
+
sound._seek = sound._start || 0;
|
|
1431
|
+
sound._rateSeek = 0;
|
|
1432
|
+
self._clearTimer(sound._id);
|
|
1433
|
+
self._cleanBuffer(sound._node);
|
|
1434
|
+
Howler3._autoSuspend();
|
|
1435
|
+
}
|
|
1436
|
+
if (!self._webAudio && !loop) {
|
|
1437
|
+
self.stop(sound._id, true);
|
|
1438
|
+
}
|
|
1439
|
+
return self;
|
|
1440
|
+
},
|
|
1441
|
+
/**
|
|
1442
|
+
* Clear the end timer for a sound playback.
|
|
1443
|
+
* @param {Number} id The sound ID.
|
|
1444
|
+
* @return {Howl}
|
|
1445
|
+
*/
|
|
1446
|
+
_clearTimer: function(id) {
|
|
1447
|
+
var self = this;
|
|
1448
|
+
if (self._endTimers[id]) {
|
|
1449
|
+
if (typeof self._endTimers[id] !== "function") {
|
|
1450
|
+
clearTimeout(self._endTimers[id]);
|
|
1451
|
+
} else {
|
|
1452
|
+
var sound = self._soundById(id);
|
|
1453
|
+
if (sound && sound._node) {
|
|
1454
|
+
sound._node.removeEventListener("ended", self._endTimers[id], false);
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
delete self._endTimers[id];
|
|
1458
|
+
}
|
|
1459
|
+
return self;
|
|
1460
|
+
},
|
|
1461
|
+
/**
|
|
1462
|
+
* Return the sound identified by this ID, or return null.
|
|
1463
|
+
* @param {Number} id Sound ID
|
|
1464
|
+
* @return {Object} Sound object or null.
|
|
1465
|
+
*/
|
|
1466
|
+
_soundById: function(id) {
|
|
1467
|
+
var self = this;
|
|
1468
|
+
for (var i = 0; i < self._sounds.length; i++) {
|
|
1469
|
+
if (id === self._sounds[i]._id) {
|
|
1470
|
+
return self._sounds[i];
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1473
|
+
return null;
|
|
1474
|
+
},
|
|
1475
|
+
/**
|
|
1476
|
+
* Return an inactive sound from the pool or create a new one.
|
|
1477
|
+
* @return {Sound} Sound playback object.
|
|
1478
|
+
*/
|
|
1479
|
+
_inactiveSound: function() {
|
|
1480
|
+
var self = this;
|
|
1481
|
+
self._drain();
|
|
1482
|
+
for (var i = 0; i < self._sounds.length; i++) {
|
|
1483
|
+
if (self._sounds[i]._ended) {
|
|
1484
|
+
return self._sounds[i].reset();
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
return new Sound2(self);
|
|
1488
|
+
},
|
|
1489
|
+
/**
|
|
1490
|
+
* Drain excess inactive sounds from the pool.
|
|
1491
|
+
*/
|
|
1492
|
+
_drain: function() {
|
|
1493
|
+
var self = this;
|
|
1494
|
+
var limit = self._pool;
|
|
1495
|
+
var cnt = 0;
|
|
1496
|
+
var i = 0;
|
|
1497
|
+
if (self._sounds.length < limit) {
|
|
1498
|
+
return;
|
|
1499
|
+
}
|
|
1500
|
+
for (i = 0; i < self._sounds.length; i++) {
|
|
1501
|
+
if (self._sounds[i]._ended) {
|
|
1502
|
+
cnt++;
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
for (i = self._sounds.length - 1; i >= 0; i--) {
|
|
1506
|
+
if (cnt <= limit) {
|
|
1507
|
+
return;
|
|
1508
|
+
}
|
|
1509
|
+
if (self._sounds[i]._ended) {
|
|
1510
|
+
if (self._webAudio && self._sounds[i]._node) {
|
|
1511
|
+
self._sounds[i]._node.disconnect(0);
|
|
1512
|
+
}
|
|
1513
|
+
self._sounds.splice(i, 1);
|
|
1514
|
+
cnt--;
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
},
|
|
1518
|
+
/**
|
|
1519
|
+
* Get all ID's from the sounds pool.
|
|
1520
|
+
* @param {Number} id Only return one ID if one is passed.
|
|
1521
|
+
* @return {Array} Array of IDs.
|
|
1522
|
+
*/
|
|
1523
|
+
_getSoundIds: function(id) {
|
|
1524
|
+
var self = this;
|
|
1525
|
+
if (typeof id === "undefined") {
|
|
1526
|
+
var ids = [];
|
|
1527
|
+
for (var i = 0; i < self._sounds.length; i++) {
|
|
1528
|
+
ids.push(self._sounds[i]._id);
|
|
1529
|
+
}
|
|
1530
|
+
return ids;
|
|
1531
|
+
} else {
|
|
1532
|
+
return [id];
|
|
1533
|
+
}
|
|
1534
|
+
},
|
|
1535
|
+
/**
|
|
1536
|
+
* Load the sound back into the buffer source.
|
|
1537
|
+
* @param {Sound} sound The sound object to work with.
|
|
1538
|
+
* @return {Howl}
|
|
1539
|
+
*/
|
|
1540
|
+
_refreshBuffer: function(sound) {
|
|
1541
|
+
var self = this;
|
|
1542
|
+
sound._node.bufferSource = Howler3.ctx.createBufferSource();
|
|
1543
|
+
sound._node.bufferSource.buffer = cache[self._src];
|
|
1544
|
+
if (sound._panner) {
|
|
1545
|
+
sound._node.bufferSource.connect(sound._panner);
|
|
1546
|
+
} else {
|
|
1547
|
+
sound._node.bufferSource.connect(sound._node);
|
|
1548
|
+
}
|
|
1549
|
+
sound._node.bufferSource.loop = sound._loop;
|
|
1550
|
+
if (sound._loop) {
|
|
1551
|
+
sound._node.bufferSource.loopStart = sound._start || 0;
|
|
1552
|
+
sound._node.bufferSource.loopEnd = sound._stop || 0;
|
|
1553
|
+
}
|
|
1554
|
+
sound._node.bufferSource.playbackRate.setValueAtTime(sound._rate, Howler3.ctx.currentTime);
|
|
1555
|
+
return self;
|
|
1556
|
+
},
|
|
1557
|
+
/**
|
|
1558
|
+
* Prevent memory leaks by cleaning up the buffer source after playback.
|
|
1559
|
+
* @param {Object} node Sound's audio node containing the buffer source.
|
|
1560
|
+
* @return {Howl}
|
|
1561
|
+
*/
|
|
1562
|
+
_cleanBuffer: function(node) {
|
|
1563
|
+
var self = this;
|
|
1564
|
+
var isIOS = Howler3._navigator && Howler3._navigator.vendor.indexOf("Apple") >= 0;
|
|
1565
|
+
if (!node.bufferSource) {
|
|
1566
|
+
return self;
|
|
1567
|
+
}
|
|
1568
|
+
if (Howler3._scratchBuffer && node.bufferSource) {
|
|
1569
|
+
node.bufferSource.onended = null;
|
|
1570
|
+
node.bufferSource.disconnect(0);
|
|
1571
|
+
if (isIOS) {
|
|
1572
|
+
try {
|
|
1573
|
+
node.bufferSource.buffer = Howler3._scratchBuffer;
|
|
1574
|
+
} catch (e) {
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
node.bufferSource = null;
|
|
1579
|
+
return self;
|
|
1580
|
+
},
|
|
1581
|
+
/**
|
|
1582
|
+
* Set the source to a 0-second silence to stop any downloading (except in IE).
|
|
1583
|
+
* @param {Object} node Audio node to clear.
|
|
1584
|
+
*/
|
|
1585
|
+
_clearSound: function(node) {
|
|
1586
|
+
var checkIE = /MSIE |Trident\//.test(Howler3._navigator && Howler3._navigator.userAgent);
|
|
1587
|
+
if (!checkIE) {
|
|
1588
|
+
node.src = "data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA";
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
};
|
|
1592
|
+
var Sound2 = function(howl) {
|
|
1593
|
+
this._parent = howl;
|
|
1594
|
+
this.init();
|
|
1595
|
+
};
|
|
1596
|
+
Sound2.prototype = {
|
|
1597
|
+
/**
|
|
1598
|
+
* Initialize a new Sound object.
|
|
1599
|
+
* @return {Sound}
|
|
1600
|
+
*/
|
|
1601
|
+
init: function() {
|
|
1602
|
+
var self = this;
|
|
1603
|
+
var parent = self._parent;
|
|
1604
|
+
self._muted = parent._muted;
|
|
1605
|
+
self._loop = parent._loop;
|
|
1606
|
+
self._volume = parent._volume;
|
|
1607
|
+
self._rate = parent._rate;
|
|
1608
|
+
self._seek = 0;
|
|
1609
|
+
self._paused = true;
|
|
1610
|
+
self._ended = true;
|
|
1611
|
+
self._sprite = "__default";
|
|
1612
|
+
self._id = ++Howler3._counter;
|
|
1613
|
+
parent._sounds.push(self);
|
|
1614
|
+
self.create();
|
|
1615
|
+
return self;
|
|
1616
|
+
},
|
|
1617
|
+
/**
|
|
1618
|
+
* Create and setup a new sound object, whether HTML5 Audio or Web Audio.
|
|
1619
|
+
* @return {Sound}
|
|
1620
|
+
*/
|
|
1621
|
+
create: function() {
|
|
1622
|
+
var self = this;
|
|
1623
|
+
var parent = self._parent;
|
|
1624
|
+
var volume = Howler3._muted || self._muted || self._parent._muted ? 0 : self._volume;
|
|
1625
|
+
if (parent._webAudio) {
|
|
1626
|
+
self._node = typeof Howler3.ctx.createGain === "undefined" ? Howler3.ctx.createGainNode() : Howler3.ctx.createGain();
|
|
1627
|
+
self._node.gain.setValueAtTime(volume, Howler3.ctx.currentTime);
|
|
1628
|
+
self._node.paused = true;
|
|
1629
|
+
self._node.connect(Howler3.masterGain);
|
|
1630
|
+
} else if (!Howler3.noAudio) {
|
|
1631
|
+
self._node = Howler3._obtainHtml5Audio();
|
|
1632
|
+
self._errorFn = self._errorListener.bind(self);
|
|
1633
|
+
self._node.addEventListener("error", self._errorFn, false);
|
|
1634
|
+
self._loadFn = self._loadListener.bind(self);
|
|
1635
|
+
self._node.addEventListener(Howler3._canPlayEvent, self._loadFn, false);
|
|
1636
|
+
self._endFn = self._endListener.bind(self);
|
|
1637
|
+
self._node.addEventListener("ended", self._endFn, false);
|
|
1638
|
+
self._node.src = parent._src;
|
|
1639
|
+
self._node.preload = parent._preload === true ? "auto" : parent._preload;
|
|
1640
|
+
self._node.volume = volume * Howler3.volume();
|
|
1641
|
+
self._node.load();
|
|
1642
|
+
}
|
|
1643
|
+
return self;
|
|
1644
|
+
},
|
|
1645
|
+
/**
|
|
1646
|
+
* Reset the parameters of this sound to the original state (for recycle).
|
|
1647
|
+
* @return {Sound}
|
|
1648
|
+
*/
|
|
1649
|
+
reset: function() {
|
|
1650
|
+
var self = this;
|
|
1651
|
+
var parent = self._parent;
|
|
1652
|
+
self._muted = parent._muted;
|
|
1653
|
+
self._loop = parent._loop;
|
|
1654
|
+
self._volume = parent._volume;
|
|
1655
|
+
self._rate = parent._rate;
|
|
1656
|
+
self._seek = 0;
|
|
1657
|
+
self._rateSeek = 0;
|
|
1658
|
+
self._paused = true;
|
|
1659
|
+
self._ended = true;
|
|
1660
|
+
self._sprite = "__default";
|
|
1661
|
+
self._id = ++Howler3._counter;
|
|
1662
|
+
return self;
|
|
1663
|
+
},
|
|
1664
|
+
/**
|
|
1665
|
+
* HTML5 Audio error listener callback.
|
|
1666
|
+
*/
|
|
1667
|
+
_errorListener: function() {
|
|
1668
|
+
var self = this;
|
|
1669
|
+
self._parent._emit("loaderror", self._id, self._node.error ? self._node.error.code : 0);
|
|
1670
|
+
self._node.removeEventListener("error", self._errorFn, false);
|
|
1671
|
+
},
|
|
1672
|
+
/**
|
|
1673
|
+
* HTML5 Audio canplaythrough listener callback.
|
|
1674
|
+
*/
|
|
1675
|
+
_loadListener: function() {
|
|
1676
|
+
var self = this;
|
|
1677
|
+
var parent = self._parent;
|
|
1678
|
+
parent._duration = Math.ceil(self._node.duration * 10) / 10;
|
|
1679
|
+
if (Object.keys(parent._sprite).length === 0) {
|
|
1680
|
+
parent._sprite = { __default: [0, parent._duration * 1e3] };
|
|
1681
|
+
}
|
|
1682
|
+
if (parent._state !== "loaded") {
|
|
1683
|
+
parent._state = "loaded";
|
|
1684
|
+
parent._emit("load");
|
|
1685
|
+
parent._loadQueue();
|
|
1686
|
+
}
|
|
1687
|
+
self._node.removeEventListener(Howler3._canPlayEvent, self._loadFn, false);
|
|
1688
|
+
},
|
|
1689
|
+
/**
|
|
1690
|
+
* HTML5 Audio ended listener callback.
|
|
1691
|
+
*/
|
|
1692
|
+
_endListener: function() {
|
|
1693
|
+
var self = this;
|
|
1694
|
+
var parent = self._parent;
|
|
1695
|
+
if (parent._duration === Infinity) {
|
|
1696
|
+
parent._duration = Math.ceil(self._node.duration * 10) / 10;
|
|
1697
|
+
if (parent._sprite.__default[1] === Infinity) {
|
|
1698
|
+
parent._sprite.__default[1] = parent._duration * 1e3;
|
|
1699
|
+
}
|
|
1700
|
+
parent._ended(self);
|
|
1701
|
+
}
|
|
1702
|
+
self._node.removeEventListener("ended", self._endFn, false);
|
|
1703
|
+
}
|
|
1704
|
+
};
|
|
1705
|
+
var cache = {};
|
|
1706
|
+
var loadBuffer = function(self) {
|
|
1707
|
+
var url = self._src;
|
|
1708
|
+
if (cache[url]) {
|
|
1709
|
+
self._duration = cache[url].duration;
|
|
1710
|
+
loadSound(self);
|
|
1711
|
+
return;
|
|
1712
|
+
}
|
|
1713
|
+
if (/^data:[^;]+;base64,/.test(url)) {
|
|
1714
|
+
var data = atob(url.split(",")[1]);
|
|
1715
|
+
var dataView = new Uint8Array(data.length);
|
|
1716
|
+
for (var i = 0; i < data.length; ++i) {
|
|
1717
|
+
dataView[i] = data.charCodeAt(i);
|
|
1718
|
+
}
|
|
1719
|
+
decodeAudioData(dataView.buffer, self);
|
|
1720
|
+
} else {
|
|
1721
|
+
var xhr = new XMLHttpRequest();
|
|
1722
|
+
xhr.open(self._xhr.method, url, true);
|
|
1723
|
+
xhr.withCredentials = self._xhr.withCredentials;
|
|
1724
|
+
xhr.responseType = "arraybuffer";
|
|
1725
|
+
if (self._xhr.headers) {
|
|
1726
|
+
Object.keys(self._xhr.headers).forEach(function(key) {
|
|
1727
|
+
xhr.setRequestHeader(key, self._xhr.headers[key]);
|
|
1728
|
+
});
|
|
1729
|
+
}
|
|
1730
|
+
xhr.onload = function() {
|
|
1731
|
+
var code = (xhr.status + "")[0];
|
|
1732
|
+
if (code !== "0" && code !== "2" && code !== "3") {
|
|
1733
|
+
self._emit("loaderror", null, "Failed loading audio file with status: " + xhr.status + ".");
|
|
1734
|
+
return;
|
|
1735
|
+
}
|
|
1736
|
+
decodeAudioData(xhr.response, self);
|
|
1737
|
+
};
|
|
1738
|
+
xhr.onerror = function() {
|
|
1739
|
+
if (self._webAudio) {
|
|
1740
|
+
self._html5 = true;
|
|
1741
|
+
self._webAudio = false;
|
|
1742
|
+
self._sounds = [];
|
|
1743
|
+
delete cache[url];
|
|
1744
|
+
self.load();
|
|
1745
|
+
}
|
|
1746
|
+
};
|
|
1747
|
+
safeXhrSend(xhr);
|
|
1748
|
+
}
|
|
1749
|
+
};
|
|
1750
|
+
var safeXhrSend = function(xhr) {
|
|
1751
|
+
try {
|
|
1752
|
+
xhr.send();
|
|
1753
|
+
} catch (e) {
|
|
1754
|
+
xhr.onerror();
|
|
1755
|
+
}
|
|
1756
|
+
};
|
|
1757
|
+
var decodeAudioData = function(arraybuffer, self) {
|
|
1758
|
+
var error = function() {
|
|
1759
|
+
self._emit("loaderror", null, "Decoding audio data failed.");
|
|
1760
|
+
};
|
|
1761
|
+
var success = function(buffer) {
|
|
1762
|
+
if (buffer && self._sounds.length > 0) {
|
|
1763
|
+
cache[self._src] = buffer;
|
|
1764
|
+
loadSound(self, buffer);
|
|
1765
|
+
} else {
|
|
1766
|
+
error();
|
|
1767
|
+
}
|
|
1768
|
+
};
|
|
1769
|
+
if (typeof Promise !== "undefined" && Howler3.ctx.decodeAudioData.length === 1) {
|
|
1770
|
+
Howler3.ctx.decodeAudioData(arraybuffer).then(success).catch(error);
|
|
1771
|
+
} else {
|
|
1772
|
+
Howler3.ctx.decodeAudioData(arraybuffer, success, error);
|
|
1773
|
+
}
|
|
1774
|
+
};
|
|
1775
|
+
var loadSound = function(self, buffer) {
|
|
1776
|
+
if (buffer && !self._duration) {
|
|
1777
|
+
self._duration = buffer.duration;
|
|
1778
|
+
}
|
|
1779
|
+
if (Object.keys(self._sprite).length === 0) {
|
|
1780
|
+
self._sprite = { __default: [0, self._duration * 1e3] };
|
|
1781
|
+
}
|
|
1782
|
+
if (self._state !== "loaded") {
|
|
1783
|
+
self._state = "loaded";
|
|
1784
|
+
self._emit("load");
|
|
1785
|
+
self._loadQueue();
|
|
1786
|
+
}
|
|
1787
|
+
};
|
|
1788
|
+
var setupAudioContext = function() {
|
|
1789
|
+
if (!Howler3.usingWebAudio) {
|
|
1790
|
+
return;
|
|
1791
|
+
}
|
|
1792
|
+
try {
|
|
1793
|
+
if (typeof AudioContext !== "undefined") {
|
|
1794
|
+
Howler3.ctx = new AudioContext();
|
|
1795
|
+
} else if (typeof webkitAudioContext !== "undefined") {
|
|
1796
|
+
Howler3.ctx = new webkitAudioContext();
|
|
1797
|
+
} else {
|
|
1798
|
+
Howler3.usingWebAudio = false;
|
|
1799
|
+
}
|
|
1800
|
+
} catch (e) {
|
|
1801
|
+
Howler3.usingWebAudio = false;
|
|
1802
|
+
}
|
|
1803
|
+
if (!Howler3.ctx) {
|
|
1804
|
+
Howler3.usingWebAudio = false;
|
|
1805
|
+
}
|
|
1806
|
+
var iOS = /iP(hone|od|ad)/.test(Howler3._navigator && Howler3._navigator.platform);
|
|
1807
|
+
var appVersion = Howler3._navigator && Howler3._navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/);
|
|
1808
|
+
var version = appVersion ? parseInt(appVersion[1], 10) : null;
|
|
1809
|
+
if (iOS && version && version < 9) {
|
|
1810
|
+
var safari = /safari/.test(Howler3._navigator && Howler3._navigator.userAgent.toLowerCase());
|
|
1811
|
+
if (Howler3._navigator && !safari) {
|
|
1812
|
+
Howler3.usingWebAudio = false;
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
if (Howler3.usingWebAudio) {
|
|
1816
|
+
Howler3.masterGain = typeof Howler3.ctx.createGain === "undefined" ? Howler3.ctx.createGainNode() : Howler3.ctx.createGain();
|
|
1817
|
+
Howler3.masterGain.gain.setValueAtTime(Howler3._muted ? 0 : Howler3._volume, Howler3.ctx.currentTime);
|
|
1818
|
+
Howler3.masterGain.connect(Howler3.ctx.destination);
|
|
1819
|
+
}
|
|
1820
|
+
Howler3._setup();
|
|
1821
|
+
};
|
|
1822
|
+
if (typeof define === "function" && define.amd) {
|
|
1823
|
+
define([], function() {
|
|
1824
|
+
return {
|
|
1825
|
+
Howler: Howler3,
|
|
1826
|
+
Howl: Howl3
|
|
1827
|
+
};
|
|
1828
|
+
});
|
|
1829
|
+
}
|
|
1830
|
+
if (typeof exports !== "undefined") {
|
|
1831
|
+
exports.Howler = Howler3;
|
|
1832
|
+
exports.Howl = Howl3;
|
|
1833
|
+
}
|
|
1834
|
+
if (typeof global !== "undefined") {
|
|
1835
|
+
global.HowlerGlobal = HowlerGlobal2;
|
|
1836
|
+
global.Howler = Howler3;
|
|
1837
|
+
global.Howl = Howl3;
|
|
1838
|
+
global.Sound = Sound2;
|
|
1839
|
+
} else if (typeof window !== "undefined") {
|
|
1840
|
+
window.HowlerGlobal = HowlerGlobal2;
|
|
1841
|
+
window.Howler = Howler3;
|
|
1842
|
+
window.Howl = Howl3;
|
|
1843
|
+
window.Sound = Sound2;
|
|
1844
|
+
}
|
|
1845
|
+
})();
|
|
1846
|
+
(function() {
|
|
1847
|
+
"use strict";
|
|
1848
|
+
HowlerGlobal.prototype._pos = [0, 0, 0];
|
|
1849
|
+
HowlerGlobal.prototype._orientation = [0, 0, -1, 0, 1, 0];
|
|
1850
|
+
HowlerGlobal.prototype.stereo = function(pan) {
|
|
1851
|
+
var self = this;
|
|
1852
|
+
if (!self.ctx || !self.ctx.listener) {
|
|
1853
|
+
return self;
|
|
1854
|
+
}
|
|
1855
|
+
for (var i = self._howls.length - 1; i >= 0; i--) {
|
|
1856
|
+
self._howls[i].stereo(pan);
|
|
1857
|
+
}
|
|
1858
|
+
return self;
|
|
1859
|
+
};
|
|
1860
|
+
HowlerGlobal.prototype.pos = function(x, y, z) {
|
|
1861
|
+
var self = this;
|
|
1862
|
+
if (!self.ctx || !self.ctx.listener) {
|
|
1863
|
+
return self;
|
|
1864
|
+
}
|
|
1865
|
+
y = typeof y !== "number" ? self._pos[1] : y;
|
|
1866
|
+
z = typeof z !== "number" ? self._pos[2] : z;
|
|
1867
|
+
if (typeof x === "number") {
|
|
1868
|
+
self._pos = [x, y, z];
|
|
1869
|
+
if (typeof self.ctx.listener.positionX !== "undefined") {
|
|
1870
|
+
self.ctx.listener.positionX.setTargetAtTime(self._pos[0], Howler.ctx.currentTime, 0.1);
|
|
1871
|
+
self.ctx.listener.positionY.setTargetAtTime(self._pos[1], Howler.ctx.currentTime, 0.1);
|
|
1872
|
+
self.ctx.listener.positionZ.setTargetAtTime(self._pos[2], Howler.ctx.currentTime, 0.1);
|
|
1873
|
+
} else {
|
|
1874
|
+
self.ctx.listener.setPosition(self._pos[0], self._pos[1], self._pos[2]);
|
|
1875
|
+
}
|
|
1876
|
+
} else {
|
|
1877
|
+
return self._pos;
|
|
1878
|
+
}
|
|
1879
|
+
return self;
|
|
1880
|
+
};
|
|
1881
|
+
HowlerGlobal.prototype.orientation = function(x, y, z, xUp, yUp, zUp) {
|
|
1882
|
+
var self = this;
|
|
1883
|
+
if (!self.ctx || !self.ctx.listener) {
|
|
1884
|
+
return self;
|
|
1885
|
+
}
|
|
1886
|
+
var or = self._orientation;
|
|
1887
|
+
y = typeof y !== "number" ? or[1] : y;
|
|
1888
|
+
z = typeof z !== "number" ? or[2] : z;
|
|
1889
|
+
xUp = typeof xUp !== "number" ? or[3] : xUp;
|
|
1890
|
+
yUp = typeof yUp !== "number" ? or[4] : yUp;
|
|
1891
|
+
zUp = typeof zUp !== "number" ? or[5] : zUp;
|
|
1892
|
+
if (typeof x === "number") {
|
|
1893
|
+
self._orientation = [x, y, z, xUp, yUp, zUp];
|
|
1894
|
+
if (typeof self.ctx.listener.forwardX !== "undefined") {
|
|
1895
|
+
self.ctx.listener.forwardX.setTargetAtTime(x, Howler.ctx.currentTime, 0.1);
|
|
1896
|
+
self.ctx.listener.forwardY.setTargetAtTime(y, Howler.ctx.currentTime, 0.1);
|
|
1897
|
+
self.ctx.listener.forwardZ.setTargetAtTime(z, Howler.ctx.currentTime, 0.1);
|
|
1898
|
+
self.ctx.listener.upX.setTargetAtTime(xUp, Howler.ctx.currentTime, 0.1);
|
|
1899
|
+
self.ctx.listener.upY.setTargetAtTime(yUp, Howler.ctx.currentTime, 0.1);
|
|
1900
|
+
self.ctx.listener.upZ.setTargetAtTime(zUp, Howler.ctx.currentTime, 0.1);
|
|
1901
|
+
} else {
|
|
1902
|
+
self.ctx.listener.setOrientation(x, y, z, xUp, yUp, zUp);
|
|
1903
|
+
}
|
|
1904
|
+
} else {
|
|
1905
|
+
return or;
|
|
1906
|
+
}
|
|
1907
|
+
return self;
|
|
1908
|
+
};
|
|
1909
|
+
Howl.prototype.init = /* @__PURE__ */ (function(_super) {
|
|
1910
|
+
return function(o) {
|
|
1911
|
+
var self = this;
|
|
1912
|
+
self._orientation = o.orientation || [1, 0, 0];
|
|
1913
|
+
self._stereo = o.stereo || null;
|
|
1914
|
+
self._pos = o.pos || null;
|
|
1915
|
+
self._pannerAttr = {
|
|
1916
|
+
coneInnerAngle: typeof o.coneInnerAngle !== "undefined" ? o.coneInnerAngle : 360,
|
|
1917
|
+
coneOuterAngle: typeof o.coneOuterAngle !== "undefined" ? o.coneOuterAngle : 360,
|
|
1918
|
+
coneOuterGain: typeof o.coneOuterGain !== "undefined" ? o.coneOuterGain : 0,
|
|
1919
|
+
distanceModel: typeof o.distanceModel !== "undefined" ? o.distanceModel : "inverse",
|
|
1920
|
+
maxDistance: typeof o.maxDistance !== "undefined" ? o.maxDistance : 1e4,
|
|
1921
|
+
panningModel: typeof o.panningModel !== "undefined" ? o.panningModel : "HRTF",
|
|
1922
|
+
refDistance: typeof o.refDistance !== "undefined" ? o.refDistance : 1,
|
|
1923
|
+
rolloffFactor: typeof o.rolloffFactor !== "undefined" ? o.rolloffFactor : 1
|
|
1924
|
+
};
|
|
1925
|
+
self._onstereo = o.onstereo ? [{ fn: o.onstereo }] : [];
|
|
1926
|
+
self._onpos = o.onpos ? [{ fn: o.onpos }] : [];
|
|
1927
|
+
self._onorientation = o.onorientation ? [{ fn: o.onorientation }] : [];
|
|
1928
|
+
return _super.call(this, o);
|
|
1929
|
+
};
|
|
1930
|
+
})(Howl.prototype.init);
|
|
1931
|
+
Howl.prototype.stereo = function(pan, id) {
|
|
1932
|
+
var self = this;
|
|
1933
|
+
if (!self._webAudio) {
|
|
1934
|
+
return self;
|
|
1935
|
+
}
|
|
1936
|
+
if (self._state !== "loaded") {
|
|
1937
|
+
self._queue.push({
|
|
1938
|
+
event: "stereo",
|
|
1939
|
+
action: function() {
|
|
1940
|
+
self.stereo(pan, id);
|
|
1941
|
+
}
|
|
1942
|
+
});
|
|
1943
|
+
return self;
|
|
1944
|
+
}
|
|
1945
|
+
var pannerType = typeof Howler.ctx.createStereoPanner === "undefined" ? "spatial" : "stereo";
|
|
1946
|
+
if (typeof id === "undefined") {
|
|
1947
|
+
if (typeof pan === "number") {
|
|
1948
|
+
self._stereo = pan;
|
|
1949
|
+
self._pos = [pan, 0, 0];
|
|
1950
|
+
} else {
|
|
1951
|
+
return self._stereo;
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
var ids = self._getSoundIds(id);
|
|
1955
|
+
for (var i = 0; i < ids.length; i++) {
|
|
1956
|
+
var sound = self._soundById(ids[i]);
|
|
1957
|
+
if (sound) {
|
|
1958
|
+
if (typeof pan === "number") {
|
|
1959
|
+
sound._stereo = pan;
|
|
1960
|
+
sound._pos = [pan, 0, 0];
|
|
1961
|
+
if (sound._node) {
|
|
1962
|
+
sound._pannerAttr.panningModel = "equalpower";
|
|
1963
|
+
if (!sound._panner || !sound._panner.pan) {
|
|
1964
|
+
setupPanner(sound, pannerType);
|
|
1965
|
+
}
|
|
1966
|
+
if (pannerType === "spatial") {
|
|
1967
|
+
if (typeof sound._panner.positionX !== "undefined") {
|
|
1968
|
+
sound._panner.positionX.setValueAtTime(pan, Howler.ctx.currentTime);
|
|
1969
|
+
sound._panner.positionY.setValueAtTime(0, Howler.ctx.currentTime);
|
|
1970
|
+
sound._panner.positionZ.setValueAtTime(0, Howler.ctx.currentTime);
|
|
1971
|
+
} else {
|
|
1972
|
+
sound._panner.setPosition(pan, 0, 0);
|
|
1973
|
+
}
|
|
1974
|
+
} else {
|
|
1975
|
+
sound._panner.pan.setValueAtTime(pan, Howler.ctx.currentTime);
|
|
1976
|
+
}
|
|
1977
|
+
}
|
|
1978
|
+
self._emit("stereo", sound._id);
|
|
1979
|
+
} else {
|
|
1980
|
+
return sound._stereo;
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
return self;
|
|
1985
|
+
};
|
|
1986
|
+
Howl.prototype.pos = function(x, y, z, id) {
|
|
1987
|
+
var self = this;
|
|
1988
|
+
if (!self._webAudio) {
|
|
1989
|
+
return self;
|
|
1990
|
+
}
|
|
1991
|
+
if (self._state !== "loaded") {
|
|
1992
|
+
self._queue.push({
|
|
1993
|
+
event: "pos",
|
|
1994
|
+
action: function() {
|
|
1995
|
+
self.pos(x, y, z, id);
|
|
1996
|
+
}
|
|
1997
|
+
});
|
|
1998
|
+
return self;
|
|
1999
|
+
}
|
|
2000
|
+
y = typeof y !== "number" ? 0 : y;
|
|
2001
|
+
z = typeof z !== "number" ? -0.5 : z;
|
|
2002
|
+
if (typeof id === "undefined") {
|
|
2003
|
+
if (typeof x === "number") {
|
|
2004
|
+
self._pos = [x, y, z];
|
|
2005
|
+
} else {
|
|
2006
|
+
return self._pos;
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
var ids = self._getSoundIds(id);
|
|
2010
|
+
for (var i = 0; i < ids.length; i++) {
|
|
2011
|
+
var sound = self._soundById(ids[i]);
|
|
2012
|
+
if (sound) {
|
|
2013
|
+
if (typeof x === "number") {
|
|
2014
|
+
sound._pos = [x, y, z];
|
|
2015
|
+
if (sound._node) {
|
|
2016
|
+
if (!sound._panner || sound._panner.pan) {
|
|
2017
|
+
setupPanner(sound, "spatial");
|
|
2018
|
+
}
|
|
2019
|
+
if (typeof sound._panner.positionX !== "undefined") {
|
|
2020
|
+
sound._panner.positionX.setValueAtTime(x, Howler.ctx.currentTime);
|
|
2021
|
+
sound._panner.positionY.setValueAtTime(y, Howler.ctx.currentTime);
|
|
2022
|
+
sound._panner.positionZ.setValueAtTime(z, Howler.ctx.currentTime);
|
|
2023
|
+
} else {
|
|
2024
|
+
sound._panner.setPosition(x, y, z);
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
self._emit("pos", sound._id);
|
|
2028
|
+
} else {
|
|
2029
|
+
return sound._pos;
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
return self;
|
|
2034
|
+
};
|
|
2035
|
+
Howl.prototype.orientation = function(x, y, z, id) {
|
|
2036
|
+
var self = this;
|
|
2037
|
+
if (!self._webAudio) {
|
|
2038
|
+
return self;
|
|
2039
|
+
}
|
|
2040
|
+
if (self._state !== "loaded") {
|
|
2041
|
+
self._queue.push({
|
|
2042
|
+
event: "orientation",
|
|
2043
|
+
action: function() {
|
|
2044
|
+
self.orientation(x, y, z, id);
|
|
2045
|
+
}
|
|
2046
|
+
});
|
|
2047
|
+
return self;
|
|
2048
|
+
}
|
|
2049
|
+
y = typeof y !== "number" ? self._orientation[1] : y;
|
|
2050
|
+
z = typeof z !== "number" ? self._orientation[2] : z;
|
|
2051
|
+
if (typeof id === "undefined") {
|
|
2052
|
+
if (typeof x === "number") {
|
|
2053
|
+
self._orientation = [x, y, z];
|
|
2054
|
+
} else {
|
|
2055
|
+
return self._orientation;
|
|
2056
|
+
}
|
|
2057
|
+
}
|
|
2058
|
+
var ids = self._getSoundIds(id);
|
|
2059
|
+
for (var i = 0; i < ids.length; i++) {
|
|
2060
|
+
var sound = self._soundById(ids[i]);
|
|
2061
|
+
if (sound) {
|
|
2062
|
+
if (typeof x === "number") {
|
|
2063
|
+
sound._orientation = [x, y, z];
|
|
2064
|
+
if (sound._node) {
|
|
2065
|
+
if (!sound._panner) {
|
|
2066
|
+
if (!sound._pos) {
|
|
2067
|
+
sound._pos = self._pos || [0, 0, -0.5];
|
|
2068
|
+
}
|
|
2069
|
+
setupPanner(sound, "spatial");
|
|
2070
|
+
}
|
|
2071
|
+
if (typeof sound._panner.orientationX !== "undefined") {
|
|
2072
|
+
sound._panner.orientationX.setValueAtTime(x, Howler.ctx.currentTime);
|
|
2073
|
+
sound._panner.orientationY.setValueAtTime(y, Howler.ctx.currentTime);
|
|
2074
|
+
sound._panner.orientationZ.setValueAtTime(z, Howler.ctx.currentTime);
|
|
2075
|
+
} else {
|
|
2076
|
+
sound._panner.setOrientation(x, y, z);
|
|
2077
|
+
}
|
|
2078
|
+
}
|
|
2079
|
+
self._emit("orientation", sound._id);
|
|
2080
|
+
} else {
|
|
2081
|
+
return sound._orientation;
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
return self;
|
|
2086
|
+
};
|
|
2087
|
+
Howl.prototype.pannerAttr = function() {
|
|
2088
|
+
var self = this;
|
|
2089
|
+
var args = arguments;
|
|
2090
|
+
var o, id, sound;
|
|
2091
|
+
if (!self._webAudio) {
|
|
2092
|
+
return self;
|
|
2093
|
+
}
|
|
2094
|
+
if (args.length === 0) {
|
|
2095
|
+
return self._pannerAttr;
|
|
2096
|
+
} else if (args.length === 1) {
|
|
2097
|
+
if (typeof args[0] === "object") {
|
|
2098
|
+
o = args[0];
|
|
2099
|
+
if (typeof id === "undefined") {
|
|
2100
|
+
if (!o.pannerAttr) {
|
|
2101
|
+
o.pannerAttr = {
|
|
2102
|
+
coneInnerAngle: o.coneInnerAngle,
|
|
2103
|
+
coneOuterAngle: o.coneOuterAngle,
|
|
2104
|
+
coneOuterGain: o.coneOuterGain,
|
|
2105
|
+
distanceModel: o.distanceModel,
|
|
2106
|
+
maxDistance: o.maxDistance,
|
|
2107
|
+
refDistance: o.refDistance,
|
|
2108
|
+
rolloffFactor: o.rolloffFactor,
|
|
2109
|
+
panningModel: o.panningModel
|
|
2110
|
+
};
|
|
2111
|
+
}
|
|
2112
|
+
self._pannerAttr = {
|
|
2113
|
+
coneInnerAngle: typeof o.pannerAttr.coneInnerAngle !== "undefined" ? o.pannerAttr.coneInnerAngle : self._coneInnerAngle,
|
|
2114
|
+
coneOuterAngle: typeof o.pannerAttr.coneOuterAngle !== "undefined" ? o.pannerAttr.coneOuterAngle : self._coneOuterAngle,
|
|
2115
|
+
coneOuterGain: typeof o.pannerAttr.coneOuterGain !== "undefined" ? o.pannerAttr.coneOuterGain : self._coneOuterGain,
|
|
2116
|
+
distanceModel: typeof o.pannerAttr.distanceModel !== "undefined" ? o.pannerAttr.distanceModel : self._distanceModel,
|
|
2117
|
+
maxDistance: typeof o.pannerAttr.maxDistance !== "undefined" ? o.pannerAttr.maxDistance : self._maxDistance,
|
|
2118
|
+
refDistance: typeof o.pannerAttr.refDistance !== "undefined" ? o.pannerAttr.refDistance : self._refDistance,
|
|
2119
|
+
rolloffFactor: typeof o.pannerAttr.rolloffFactor !== "undefined" ? o.pannerAttr.rolloffFactor : self._rolloffFactor,
|
|
2120
|
+
panningModel: typeof o.pannerAttr.panningModel !== "undefined" ? o.pannerAttr.panningModel : self._panningModel
|
|
2121
|
+
};
|
|
2122
|
+
}
|
|
2123
|
+
} else {
|
|
2124
|
+
sound = self._soundById(parseInt(args[0], 10));
|
|
2125
|
+
return sound ? sound._pannerAttr : self._pannerAttr;
|
|
2126
|
+
}
|
|
2127
|
+
} else if (args.length === 2) {
|
|
2128
|
+
o = args[0];
|
|
2129
|
+
id = parseInt(args[1], 10);
|
|
2130
|
+
}
|
|
2131
|
+
var ids = self._getSoundIds(id);
|
|
2132
|
+
for (var i = 0; i < ids.length; i++) {
|
|
2133
|
+
sound = self._soundById(ids[i]);
|
|
2134
|
+
if (sound) {
|
|
2135
|
+
var pa = sound._pannerAttr;
|
|
2136
|
+
pa = {
|
|
2137
|
+
coneInnerAngle: typeof o.coneInnerAngle !== "undefined" ? o.coneInnerAngle : pa.coneInnerAngle,
|
|
2138
|
+
coneOuterAngle: typeof o.coneOuterAngle !== "undefined" ? o.coneOuterAngle : pa.coneOuterAngle,
|
|
2139
|
+
coneOuterGain: typeof o.coneOuterGain !== "undefined" ? o.coneOuterGain : pa.coneOuterGain,
|
|
2140
|
+
distanceModel: typeof o.distanceModel !== "undefined" ? o.distanceModel : pa.distanceModel,
|
|
2141
|
+
maxDistance: typeof o.maxDistance !== "undefined" ? o.maxDistance : pa.maxDistance,
|
|
2142
|
+
refDistance: typeof o.refDistance !== "undefined" ? o.refDistance : pa.refDistance,
|
|
2143
|
+
rolloffFactor: typeof o.rolloffFactor !== "undefined" ? o.rolloffFactor : pa.rolloffFactor,
|
|
2144
|
+
panningModel: typeof o.panningModel !== "undefined" ? o.panningModel : pa.panningModel
|
|
2145
|
+
};
|
|
2146
|
+
var panner = sound._panner;
|
|
2147
|
+
if (!panner) {
|
|
2148
|
+
if (!sound._pos) {
|
|
2149
|
+
sound._pos = self._pos || [0, 0, -0.5];
|
|
2150
|
+
}
|
|
2151
|
+
setupPanner(sound, "spatial");
|
|
2152
|
+
panner = sound._panner;
|
|
2153
|
+
}
|
|
2154
|
+
panner.coneInnerAngle = pa.coneInnerAngle;
|
|
2155
|
+
panner.coneOuterAngle = pa.coneOuterAngle;
|
|
2156
|
+
panner.coneOuterGain = pa.coneOuterGain;
|
|
2157
|
+
panner.distanceModel = pa.distanceModel;
|
|
2158
|
+
panner.maxDistance = pa.maxDistance;
|
|
2159
|
+
panner.refDistance = pa.refDistance;
|
|
2160
|
+
panner.rolloffFactor = pa.rolloffFactor;
|
|
2161
|
+
panner.panningModel = pa.panningModel;
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
return self;
|
|
2165
|
+
};
|
|
2166
|
+
Sound.prototype.init = /* @__PURE__ */ (function(_super) {
|
|
2167
|
+
return function() {
|
|
2168
|
+
var self = this;
|
|
2169
|
+
var parent = self._parent;
|
|
2170
|
+
self._orientation = parent._orientation;
|
|
2171
|
+
self._stereo = parent._stereo;
|
|
2172
|
+
self._pos = parent._pos;
|
|
2173
|
+
self._pannerAttr = parent._pannerAttr;
|
|
2174
|
+
_super.call(this);
|
|
2175
|
+
if (self._stereo) {
|
|
2176
|
+
parent.stereo(self._stereo);
|
|
2177
|
+
} else if (self._pos) {
|
|
2178
|
+
parent.pos(self._pos[0], self._pos[1], self._pos[2], self._id);
|
|
2179
|
+
}
|
|
2180
|
+
};
|
|
2181
|
+
})(Sound.prototype.init);
|
|
2182
|
+
Sound.prototype.reset = /* @__PURE__ */ (function(_super) {
|
|
2183
|
+
return function() {
|
|
2184
|
+
var self = this;
|
|
2185
|
+
var parent = self._parent;
|
|
2186
|
+
self._orientation = parent._orientation;
|
|
2187
|
+
self._stereo = parent._stereo;
|
|
2188
|
+
self._pos = parent._pos;
|
|
2189
|
+
self._pannerAttr = parent._pannerAttr;
|
|
2190
|
+
if (self._stereo) {
|
|
2191
|
+
parent.stereo(self._stereo);
|
|
2192
|
+
} else if (self._pos) {
|
|
2193
|
+
parent.pos(self._pos[0], self._pos[1], self._pos[2], self._id);
|
|
2194
|
+
} else if (self._panner) {
|
|
2195
|
+
self._panner.disconnect(0);
|
|
2196
|
+
self._panner = void 0;
|
|
2197
|
+
parent._refreshBuffer(self);
|
|
2198
|
+
}
|
|
2199
|
+
return _super.call(this);
|
|
2200
|
+
};
|
|
2201
|
+
})(Sound.prototype.reset);
|
|
2202
|
+
var setupPanner = function(sound, type) {
|
|
2203
|
+
type = type || "spatial";
|
|
2204
|
+
if (type === "spatial") {
|
|
2205
|
+
sound._panner = Howler.ctx.createPanner();
|
|
2206
|
+
sound._panner.coneInnerAngle = sound._pannerAttr.coneInnerAngle;
|
|
2207
|
+
sound._panner.coneOuterAngle = sound._pannerAttr.coneOuterAngle;
|
|
2208
|
+
sound._panner.coneOuterGain = sound._pannerAttr.coneOuterGain;
|
|
2209
|
+
sound._panner.distanceModel = sound._pannerAttr.distanceModel;
|
|
2210
|
+
sound._panner.maxDistance = sound._pannerAttr.maxDistance;
|
|
2211
|
+
sound._panner.refDistance = sound._pannerAttr.refDistance;
|
|
2212
|
+
sound._panner.rolloffFactor = sound._pannerAttr.rolloffFactor;
|
|
2213
|
+
sound._panner.panningModel = sound._pannerAttr.panningModel;
|
|
2214
|
+
if (typeof sound._panner.positionX !== "undefined") {
|
|
2215
|
+
sound._panner.positionX.setValueAtTime(sound._pos[0], Howler.ctx.currentTime);
|
|
2216
|
+
sound._panner.positionY.setValueAtTime(sound._pos[1], Howler.ctx.currentTime);
|
|
2217
|
+
sound._panner.positionZ.setValueAtTime(sound._pos[2], Howler.ctx.currentTime);
|
|
2218
|
+
} else {
|
|
2219
|
+
sound._panner.setPosition(sound._pos[0], sound._pos[1], sound._pos[2]);
|
|
2220
|
+
}
|
|
2221
|
+
if (typeof sound._panner.orientationX !== "undefined") {
|
|
2222
|
+
sound._panner.orientationX.setValueAtTime(sound._orientation[0], Howler.ctx.currentTime);
|
|
2223
|
+
sound._panner.orientationY.setValueAtTime(sound._orientation[1], Howler.ctx.currentTime);
|
|
2224
|
+
sound._panner.orientationZ.setValueAtTime(sound._orientation[2], Howler.ctx.currentTime);
|
|
2225
|
+
} else {
|
|
2226
|
+
sound._panner.setOrientation(sound._orientation[0], sound._orientation[1], sound._orientation[2]);
|
|
2227
|
+
}
|
|
2228
|
+
} else {
|
|
2229
|
+
sound._panner = Howler.ctx.createStereoPanner();
|
|
2230
|
+
sound._panner.pan.setValueAtTime(sound._stereo, Howler.ctx.currentTime);
|
|
2231
|
+
}
|
|
2232
|
+
sound._panner.connect(sound._node);
|
|
2233
|
+
if (!sound._paused) {
|
|
2234
|
+
sound._parent.pause(sound._id, true).play(sound._id, true);
|
|
2235
|
+
}
|
|
2236
|
+
};
|
|
2237
|
+
})();
|
|
2238
|
+
}
|
|
2239
|
+
});
|
|
2
2240
|
|
|
3
2241
|
// src/pano-viewer.tsx
|
|
4
2242
|
import { Canvas } from "@react-three/fiber";
|
|
@@ -4771,14 +7009,385 @@ var PanoViewer = forwardRef2(
|
|
|
4771
7009
|
}
|
|
4772
7010
|
);
|
|
4773
7011
|
|
|
7012
|
+
// src/background-audio.tsx
|
|
7013
|
+
import { useContext as useContext15, useEffect as useEffect13, useRef as useRef13 } from "react";
|
|
7014
|
+
|
|
7015
|
+
// src/audio/howl.ts
|
|
7016
|
+
var import_howler = __toESM(require_howler());
|
|
7017
|
+
import_howler.Howler.autoUnlock = true;
|
|
7018
|
+
function sourceList(src) {
|
|
7019
|
+
if (src == null) {
|
|
7020
|
+
return [];
|
|
7021
|
+
}
|
|
7022
|
+
if (typeof src === "string") {
|
|
7023
|
+
return src ? [src] : [];
|
|
7024
|
+
}
|
|
7025
|
+
return src.filter((item) => Boolean(item));
|
|
7026
|
+
}
|
|
7027
|
+
function createUnlockingHowl({
|
|
7028
|
+
src,
|
|
7029
|
+
loop,
|
|
7030
|
+
crossOrigin,
|
|
7031
|
+
isActive,
|
|
7032
|
+
shouldRetryPlay,
|
|
7033
|
+
onEnded,
|
|
7034
|
+
onPlay,
|
|
7035
|
+
onPause,
|
|
7036
|
+
onLoadError,
|
|
7037
|
+
onPlayError
|
|
7038
|
+
}) {
|
|
7039
|
+
let disposed = false;
|
|
7040
|
+
let blockedNotified = false;
|
|
7041
|
+
const unlockListeners = [];
|
|
7042
|
+
const removeUnlockListeners = () => {
|
|
7043
|
+
for (const { type, listener } of unlockListeners) {
|
|
7044
|
+
window.removeEventListener(type, listener, true);
|
|
7045
|
+
}
|
|
7046
|
+
unlockListeners.length = 0;
|
|
7047
|
+
};
|
|
7048
|
+
const instance = new import_howler.Howl({
|
|
7049
|
+
src: [...src],
|
|
7050
|
+
html5: false,
|
|
7051
|
+
preload: true,
|
|
7052
|
+
loop,
|
|
7053
|
+
xhr: crossOrigin === "use-credentials" ? { withCredentials: true } : void 0,
|
|
7054
|
+
onend: () => {
|
|
7055
|
+
if (disposed || !isActive() || instance.loop()) {
|
|
7056
|
+
return;
|
|
7057
|
+
}
|
|
7058
|
+
onEnded?.();
|
|
7059
|
+
},
|
|
7060
|
+
onplay: () => {
|
|
7061
|
+
if (!disposed && isActive()) {
|
|
7062
|
+
onPlay?.();
|
|
7063
|
+
}
|
|
7064
|
+
},
|
|
7065
|
+
onpause: () => {
|
|
7066
|
+
if (!disposed && isActive()) {
|
|
7067
|
+
onPause?.();
|
|
7068
|
+
}
|
|
7069
|
+
},
|
|
7070
|
+
onloaderror: (_soundId, error) => {
|
|
7071
|
+
if (!disposed && isActive()) {
|
|
7072
|
+
onLoadError?.(error);
|
|
7073
|
+
}
|
|
7074
|
+
},
|
|
7075
|
+
onplayerror: (_soundId, error) => {
|
|
7076
|
+
if (disposed || !isActive()) {
|
|
7077
|
+
return;
|
|
7078
|
+
}
|
|
7079
|
+
if (!blockedNotified) {
|
|
7080
|
+
blockedNotified = true;
|
|
7081
|
+
onPlayError?.(error);
|
|
7082
|
+
}
|
|
7083
|
+
const retry = () => {
|
|
7084
|
+
removeUnlockListeners();
|
|
7085
|
+
if (!disposed && isActive() && shouldRetryPlay()) {
|
|
7086
|
+
void import_howler.Howler.ctx?.resume();
|
|
7087
|
+
instance.play();
|
|
7088
|
+
}
|
|
7089
|
+
};
|
|
7090
|
+
removeUnlockListeners();
|
|
7091
|
+
unlockListeners.push({ type: "pointerdown", listener: retry });
|
|
7092
|
+
unlockListeners.push({ type: "keydown", listener: retry });
|
|
7093
|
+
window.addEventListener("pointerdown", retry, { capture: true });
|
|
7094
|
+
window.addEventListener("keydown", retry, { capture: true });
|
|
7095
|
+
}
|
|
7096
|
+
});
|
|
7097
|
+
return {
|
|
7098
|
+
howl: instance,
|
|
7099
|
+
dispose: () => {
|
|
7100
|
+
if (disposed) {
|
|
7101
|
+
return;
|
|
7102
|
+
}
|
|
7103
|
+
disposed = true;
|
|
7104
|
+
removeUnlockListeners();
|
|
7105
|
+
instance.unload();
|
|
7106
|
+
}
|
|
7107
|
+
};
|
|
7108
|
+
}
|
|
7109
|
+
|
|
7110
|
+
// src/hotspot/audio-spatial.ts
|
|
7111
|
+
import { MathUtils as MathUtils3, Vector3 as Vector35 } from "three";
|
|
7112
|
+
var LOOK_DIR = new Vector35();
|
|
7113
|
+
var SOURCE_DIR = new Vector35();
|
|
7114
|
+
var RIGHT_DIR = new Vector35();
|
|
7115
|
+
function clampAudioVolume(volume) {
|
|
7116
|
+
if (!Number.isFinite(volume)) {
|
|
7117
|
+
return 1;
|
|
7118
|
+
}
|
|
7119
|
+
return Math.max(0, Math.min(volume, 1));
|
|
7120
|
+
}
|
|
7121
|
+
function clampLookRange(range) {
|
|
7122
|
+
if (!Number.isFinite(range)) {
|
|
7123
|
+
return 360;
|
|
7124
|
+
}
|
|
7125
|
+
return Math.max(0, range);
|
|
7126
|
+
}
|
|
7127
|
+
function lookRangeGain(angleDegrees, range) {
|
|
7128
|
+
if (range > 180) {
|
|
7129
|
+
return 1;
|
|
7130
|
+
}
|
|
7131
|
+
if (range <= 0) {
|
|
7132
|
+
return 0;
|
|
7133
|
+
}
|
|
7134
|
+
return Math.max(0, Math.min(1, 1 - angleDegrees / range));
|
|
7135
|
+
}
|
|
7136
|
+
function audioSpatialFromView(camera, position, range) {
|
|
7137
|
+
camera.getWorldDirection(LOOK_DIR);
|
|
7138
|
+
SOURCE_DIR.copy(panoPositionToVector3(position)).normalize();
|
|
7139
|
+
const angleDegrees = MathUtils3.radToDeg(
|
|
7140
|
+
Math.acos(MathUtils3.clamp(LOOK_DIR.dot(SOURCE_DIR), -1, 1))
|
|
7141
|
+
);
|
|
7142
|
+
RIGHT_DIR.set(1, 0, 0).applyQuaternion(camera.quaternion);
|
|
7143
|
+
const pan = MathUtils3.clamp(
|
|
7144
|
+
Math.atan2(SOURCE_DIR.dot(RIGHT_DIR), SOURCE_DIR.dot(LOOK_DIR)) / (Math.PI / 2),
|
|
7145
|
+
-1,
|
|
7146
|
+
1
|
|
7147
|
+
);
|
|
7148
|
+
return {
|
|
7149
|
+
pan,
|
|
7150
|
+
gain: lookRangeGain(angleDegrees, range)
|
|
7151
|
+
};
|
|
7152
|
+
}
|
|
7153
|
+
|
|
7154
|
+
// src/background-audio.tsx
|
|
7155
|
+
var DEFAULT_FADE_MS = 400;
|
|
7156
|
+
function resolveFadeMs(value) {
|
|
7157
|
+
if (!Number.isFinite(value)) {
|
|
7158
|
+
return DEFAULT_FADE_MS;
|
|
7159
|
+
}
|
|
7160
|
+
return Math.max(0, value);
|
|
7161
|
+
}
|
|
7162
|
+
function resolveBackgroundAudioUrls(src, sources, sceneId) {
|
|
7163
|
+
if (sources !== void 0) {
|
|
7164
|
+
if (sceneId === void 0) {
|
|
7165
|
+
throw new Error("<BackgroundAudio> requires sceneId when sources is set.");
|
|
7166
|
+
}
|
|
7167
|
+
if (Object.prototype.hasOwnProperty.call(sources, sceneId)) {
|
|
7168
|
+
return sourceList(sources[sceneId]);
|
|
7169
|
+
}
|
|
7170
|
+
}
|
|
7171
|
+
return sourceList(src);
|
|
7172
|
+
}
|
|
7173
|
+
function applyNonSpatialMix(slot, loop, muted, volume) {
|
|
7174
|
+
slot.handle.howl.stereo(0);
|
|
7175
|
+
slot.handle.howl.loop(loop);
|
|
7176
|
+
slot.handle.howl.mute(muted);
|
|
7177
|
+
slot.handle.howl.volume(clampAudioVolume(volume));
|
|
7178
|
+
}
|
|
7179
|
+
function BackgroundAudio({
|
|
7180
|
+
src,
|
|
7181
|
+
sources,
|
|
7182
|
+
sceneId,
|
|
7183
|
+
playing,
|
|
7184
|
+
loop = true,
|
|
7185
|
+
muted = false,
|
|
7186
|
+
volume = 1,
|
|
7187
|
+
pauseWhenHidden = true,
|
|
7188
|
+
fadeMs,
|
|
7189
|
+
crossOrigin,
|
|
7190
|
+
onPlaybackStateChange,
|
|
7191
|
+
onPlaybackError,
|
|
7192
|
+
onEnded,
|
|
7193
|
+
onError
|
|
7194
|
+
}) {
|
|
7195
|
+
const controlsRef = useContext15(PanoramaViewContext);
|
|
7196
|
+
if (!controlsRef) {
|
|
7197
|
+
throw new Error("<BackgroundAudio> must be rendered inside <PanoViewer>.");
|
|
7198
|
+
}
|
|
7199
|
+
const urls = resolveBackgroundAudioUrls(src, sources, sceneId);
|
|
7200
|
+
const trackKey = urls.join("\0");
|
|
7201
|
+
const currentRef = useRef13(null);
|
|
7202
|
+
const outgoingRef = useRef13([]);
|
|
7203
|
+
const fadingInRef = useRef13(false);
|
|
7204
|
+
const isFirstTrackRef = useRef13(true);
|
|
7205
|
+
const playingRef = useRef13(playing);
|
|
7206
|
+
const loopRef = useRef13(loop);
|
|
7207
|
+
const mutedRef = useRef13(muted);
|
|
7208
|
+
const volumeRef = useRef13(volume);
|
|
7209
|
+
const fadeMsRef = useRef13(resolveFadeMs(fadeMs));
|
|
7210
|
+
const onPlaybackStateChangeRef = useRef13(onPlaybackStateChange);
|
|
7211
|
+
const onPlaybackErrorRef = useRef13(onPlaybackError);
|
|
7212
|
+
const onEndedRef = useRef13(onEnded);
|
|
7213
|
+
const onErrorRef = useRef13(onError);
|
|
7214
|
+
playingRef.current = playing;
|
|
7215
|
+
loopRef.current = loop;
|
|
7216
|
+
mutedRef.current = muted;
|
|
7217
|
+
volumeRef.current = volume;
|
|
7218
|
+
fadeMsRef.current = resolveFadeMs(fadeMs);
|
|
7219
|
+
onPlaybackStateChangeRef.current = onPlaybackStateChange;
|
|
7220
|
+
onPlaybackErrorRef.current = onPlaybackError;
|
|
7221
|
+
onEndedRef.current = onEnded;
|
|
7222
|
+
onErrorRef.current = onError;
|
|
7223
|
+
useEffect13(() => {
|
|
7224
|
+
return () => {
|
|
7225
|
+
fadingInRef.current = false;
|
|
7226
|
+
isFirstTrackRef.current = true;
|
|
7227
|
+
currentRef.current?.handle.dispose();
|
|
7228
|
+
currentRef.current = null;
|
|
7229
|
+
for (const slot of outgoingRef.current) {
|
|
7230
|
+
slot.handle.dispose();
|
|
7231
|
+
}
|
|
7232
|
+
outgoingRef.current = [];
|
|
7233
|
+
};
|
|
7234
|
+
}, []);
|
|
7235
|
+
useEffect13(() => {
|
|
7236
|
+
const previous = currentRef.current;
|
|
7237
|
+
if (previous?.key === trackKey && previous.crossOrigin === crossOrigin) {
|
|
7238
|
+
return;
|
|
7239
|
+
}
|
|
7240
|
+
const durationMs = fadeMsRef.current;
|
|
7241
|
+
const targetVolume = clampAudioVolume(volumeRef.current);
|
|
7242
|
+
const nextUrls = trackKey.length > 0 ? trackKey.split("\0") : [];
|
|
7243
|
+
const retire = (slot) => {
|
|
7244
|
+
const howl = slot.handle.howl;
|
|
7245
|
+
const from = howl.volume();
|
|
7246
|
+
outgoingRef.current.push(slot);
|
|
7247
|
+
if (durationMs <= 0 || from <= 0 || !howl.playing()) {
|
|
7248
|
+
slot.handle.dispose();
|
|
7249
|
+
outgoingRef.current = outgoingRef.current.filter((item) => item !== slot);
|
|
7250
|
+
return;
|
|
7251
|
+
}
|
|
7252
|
+
howl.once("fade", () => {
|
|
7253
|
+
slot.handle.dispose();
|
|
7254
|
+
outgoingRef.current = outgoingRef.current.filter((item) => item !== slot);
|
|
7255
|
+
});
|
|
7256
|
+
howl.fade(from, 0, durationMs);
|
|
7257
|
+
};
|
|
7258
|
+
if (nextUrls.length > 0) {
|
|
7259
|
+
const incoming = {
|
|
7260
|
+
key: trackKey,
|
|
7261
|
+
crossOrigin,
|
|
7262
|
+
handle: createUnlockingHowl({
|
|
7263
|
+
src: nextUrls,
|
|
7264
|
+
loop: loopRef.current,
|
|
7265
|
+
crossOrigin,
|
|
7266
|
+
isActive: () => currentRef.current?.key === trackKey,
|
|
7267
|
+
shouldRetryPlay: () => currentRef.current?.key === trackKey && playingRef.current,
|
|
7268
|
+
onEnded: () => {
|
|
7269
|
+
onPlaybackStateChangeRef.current?.("ended");
|
|
7270
|
+
onEndedRef.current?.();
|
|
7271
|
+
},
|
|
7272
|
+
onPlay: () => {
|
|
7273
|
+
if (fadingInRef.current && currentRef.current === incoming) {
|
|
7274
|
+
incoming.handle.howl.fade(
|
|
7275
|
+
0,
|
|
7276
|
+
clampAudioVolume(volumeRef.current),
|
|
7277
|
+
durationMs
|
|
7278
|
+
);
|
|
7279
|
+
}
|
|
7280
|
+
onPlaybackStateChangeRef.current?.("playing");
|
|
7281
|
+
},
|
|
7282
|
+
onPause: () => {
|
|
7283
|
+
onPlaybackStateChangeRef.current?.("paused");
|
|
7284
|
+
},
|
|
7285
|
+
onLoadError: (error) => {
|
|
7286
|
+
onErrorRef.current?.({ error });
|
|
7287
|
+
},
|
|
7288
|
+
onPlayError: (error) => {
|
|
7289
|
+
onPlaybackStateChangeRef.current?.("blocked");
|
|
7290
|
+
onPlaybackErrorRef.current?.(error);
|
|
7291
|
+
}
|
|
7292
|
+
})
|
|
7293
|
+
};
|
|
7294
|
+
const fadeIn = durationMs > 0 && !isFirstTrackRef.current;
|
|
7295
|
+
isFirstTrackRef.current = false;
|
|
7296
|
+
fadingInRef.current = fadeIn;
|
|
7297
|
+
applyNonSpatialMix(
|
|
7298
|
+
incoming,
|
|
7299
|
+
loopRef.current,
|
|
7300
|
+
mutedRef.current,
|
|
7301
|
+
fadeIn ? 0 : targetVolume
|
|
7302
|
+
);
|
|
7303
|
+
if (fadeIn) {
|
|
7304
|
+
incoming.handle.howl.once("fade", () => {
|
|
7305
|
+
if (currentRef.current === incoming) {
|
|
7306
|
+
fadingInRef.current = false;
|
|
7307
|
+
incoming.handle.howl.volume(clampAudioVolume(volumeRef.current));
|
|
7308
|
+
}
|
|
7309
|
+
});
|
|
7310
|
+
}
|
|
7311
|
+
currentRef.current = incoming;
|
|
7312
|
+
if (playingRef.current) {
|
|
7313
|
+
incoming.handle.howl.play();
|
|
7314
|
+
}
|
|
7315
|
+
} else {
|
|
7316
|
+
fadingInRef.current = false;
|
|
7317
|
+
isFirstTrackRef.current = false;
|
|
7318
|
+
currentRef.current = null;
|
|
7319
|
+
if (previous && durationMs > 0 && previous.handle.howl.playing()) {
|
|
7320
|
+
previous.handle.howl.once("fade", () => {
|
|
7321
|
+
onPlaybackStateChangeRef.current?.("paused");
|
|
7322
|
+
});
|
|
7323
|
+
} else if (previous) {
|
|
7324
|
+
onPlaybackStateChangeRef.current?.("paused");
|
|
7325
|
+
}
|
|
7326
|
+
}
|
|
7327
|
+
if (previous) {
|
|
7328
|
+
retire(previous);
|
|
7329
|
+
}
|
|
7330
|
+
}, [crossOrigin, trackKey]);
|
|
7331
|
+
useEffect13(() => {
|
|
7332
|
+
const howl = currentRef.current?.handle.howl;
|
|
7333
|
+
if (!howl) {
|
|
7334
|
+
return;
|
|
7335
|
+
}
|
|
7336
|
+
if (!playing) {
|
|
7337
|
+
fadingInRef.current = false;
|
|
7338
|
+
howl.pause();
|
|
7339
|
+
for (const slot of outgoingRef.current) {
|
|
7340
|
+
slot.handle.dispose();
|
|
7341
|
+
}
|
|
7342
|
+
outgoingRef.current = [];
|
|
7343
|
+
return;
|
|
7344
|
+
}
|
|
7345
|
+
howl.play();
|
|
7346
|
+
}, [playing, trackKey]);
|
|
7347
|
+
useEffect13(() => {
|
|
7348
|
+
const slot = currentRef.current;
|
|
7349
|
+
if (!slot) {
|
|
7350
|
+
return;
|
|
7351
|
+
}
|
|
7352
|
+
slot.handle.howl.loop(loop);
|
|
7353
|
+
slot.handle.howl.mute(muted);
|
|
7354
|
+
if (!fadingInRef.current) {
|
|
7355
|
+
slot.handle.howl.volume(clampAudioVolume(volume));
|
|
7356
|
+
}
|
|
7357
|
+
}, [loop, muted, trackKey, volume]);
|
|
7358
|
+
useEffect13(() => {
|
|
7359
|
+
if (!pauseWhenHidden) {
|
|
7360
|
+
return;
|
|
7361
|
+
}
|
|
7362
|
+
const handleVisibility = () => {
|
|
7363
|
+
const howl = currentRef.current?.handle.howl;
|
|
7364
|
+
if (document.hidden) {
|
|
7365
|
+
howl?.pause();
|
|
7366
|
+
for (const slot of outgoingRef.current) {
|
|
7367
|
+
slot.handle.howl.pause();
|
|
7368
|
+
}
|
|
7369
|
+
return;
|
|
7370
|
+
}
|
|
7371
|
+
if (playingRef.current && howl) {
|
|
7372
|
+
howl.play();
|
|
7373
|
+
}
|
|
7374
|
+
};
|
|
7375
|
+
document.addEventListener("visibilitychange", handleVisibility);
|
|
7376
|
+
return () => {
|
|
7377
|
+
document.removeEventListener("visibilitychange", handleVisibility);
|
|
7378
|
+
};
|
|
7379
|
+
}, [pauseWhenHidden, trackKey]);
|
|
7380
|
+
return null;
|
|
7381
|
+
}
|
|
7382
|
+
|
|
4774
7383
|
// src/pano-filter/pano-filter.tsx
|
|
4775
|
-
import { useContext as
|
|
7384
|
+
import { useContext as useContext16, useEffect as useEffect14, useMemo as useMemo8 } from "react";
|
|
4776
7385
|
function PanoFilter({
|
|
4777
7386
|
preset = "none",
|
|
4778
7387
|
intensity,
|
|
4779
7388
|
enabled = true
|
|
4780
7389
|
}) {
|
|
4781
|
-
const host =
|
|
7390
|
+
const host = useContext16(PanoFilterHostContext);
|
|
4782
7391
|
if (!host) {
|
|
4783
7392
|
throw new Error("<PanoFilter> must be rendered inside <PanoViewer>.");
|
|
4784
7393
|
}
|
|
@@ -4786,13 +7395,13 @@ function PanoFilter({
|
|
|
4786
7395
|
() => resolvePanoFilterSnapshot({ preset, intensity, enabled }),
|
|
4787
7396
|
[enabled, intensity, preset]
|
|
4788
7397
|
);
|
|
4789
|
-
|
|
7398
|
+
useEffect14(() => {
|
|
4790
7399
|
claimPanoFilter(host);
|
|
4791
7400
|
return () => {
|
|
4792
7401
|
releasePanoFilter(host);
|
|
4793
7402
|
};
|
|
4794
7403
|
}, [host]);
|
|
4795
|
-
|
|
7404
|
+
useEffect14(() => {
|
|
4796
7405
|
setPanoFilterSnapshot(host, snapshot);
|
|
4797
7406
|
}, [host, snapshot]);
|
|
4798
7407
|
return null;
|
|
@@ -4803,20 +7412,20 @@ import { useFrame as useFrame6, useThree as useThree9 } from "@react-three/fiber
|
|
|
4803
7412
|
import {
|
|
4804
7413
|
forwardRef as forwardRef3,
|
|
4805
7414
|
useCallback as useCallback7,
|
|
4806
|
-
useContext as
|
|
4807
|
-
useEffect as
|
|
7415
|
+
useContext as useContext17,
|
|
7416
|
+
useEffect as useEffect15,
|
|
4808
7417
|
useImperativeHandle as useImperativeHandle3,
|
|
4809
|
-
useRef as
|
|
7418
|
+
useRef as useRef14,
|
|
4810
7419
|
useState as useState6
|
|
4811
7420
|
} from "react";
|
|
4812
7421
|
|
|
4813
7422
|
// src/gyro-orientation.ts
|
|
4814
|
-
import { Euler as Euler2, MathUtils as
|
|
7423
|
+
import { Euler as Euler2, MathUtils as MathUtils4, Quaternion, Vector3 as Vector36 } from "three";
|
|
4815
7424
|
var DEVICE_FORWARD_CORRECTION = new Quaternion().setFromAxisAngle(
|
|
4816
|
-
new
|
|
7425
|
+
new Vector36(1, 0, 0),
|
|
4817
7426
|
-Math.PI / 2
|
|
4818
7427
|
);
|
|
4819
|
-
var SCREEN_AXIS = new
|
|
7428
|
+
var SCREEN_AXIS = new Vector36(0, 0, 1);
|
|
4820
7429
|
function getScreenOrientationAngle() {
|
|
4821
7430
|
if (typeof window === "undefined") {
|
|
4822
7431
|
return 0;
|
|
@@ -4831,30 +7440,30 @@ function getScreenOrientationAngle() {
|
|
|
4831
7440
|
function deviceOrientationToQuaternion(sample, screenOrientation) {
|
|
4832
7441
|
const alpha = Number.isFinite(sample.compassHeading) ? 360 - sample.compassHeading : sample.alpha;
|
|
4833
7442
|
const deviceEuler = new Euler2(
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
7443
|
+
MathUtils4.degToRad(sample.beta),
|
|
7444
|
+
MathUtils4.degToRad(alpha),
|
|
7445
|
+
MathUtils4.degToRad(-sample.gamma),
|
|
4837
7446
|
"YXZ"
|
|
4838
7447
|
);
|
|
4839
7448
|
const screenCorrection = new Quaternion().setFromAxisAngle(
|
|
4840
7449
|
SCREEN_AXIS,
|
|
4841
|
-
-
|
|
7450
|
+
-MathUtils4.degToRad(screenOrientation)
|
|
4842
7451
|
);
|
|
4843
7452
|
return new Quaternion().setFromEuler(deviceEuler).multiply(DEVICE_FORWARD_CORRECTION).multiply(screenCorrection).normalize();
|
|
4844
7453
|
}
|
|
4845
7454
|
function quaternionToGyroPose(quaternion) {
|
|
4846
7455
|
const euler = new Euler2().setFromQuaternion(quaternion, "YXZ");
|
|
4847
7456
|
return {
|
|
4848
|
-
yaw:
|
|
4849
|
-
pitch:
|
|
4850
|
-
roll:
|
|
7457
|
+
yaw: MathUtils4.radToDeg(-euler.y),
|
|
7458
|
+
pitch: MathUtils4.radToDeg(euler.x),
|
|
7459
|
+
roll: MathUtils4.radToDeg(euler.z)
|
|
4851
7460
|
};
|
|
4852
7461
|
}
|
|
4853
7462
|
function createRelativeCalibration(deviceQuaternion, yaw, pitch) {
|
|
4854
7463
|
const targetQuaternion = new Quaternion().setFromEuler(
|
|
4855
7464
|
new Euler2(
|
|
4856
|
-
|
|
4857
|
-
|
|
7465
|
+
MathUtils4.degToRad(pitch),
|
|
7466
|
+
MathUtils4.degToRad(-yaw),
|
|
4858
7467
|
0,
|
|
4859
7468
|
"YXZ"
|
|
4860
7469
|
)
|
|
@@ -4908,24 +7517,24 @@ var Gyro = forwardRef3(function Gyro2({
|
|
|
4908
7517
|
onDisable,
|
|
4909
7518
|
onDenied
|
|
4910
7519
|
}, ref) {
|
|
4911
|
-
const controlsRef =
|
|
4912
|
-
const eventBus =
|
|
7520
|
+
const controlsRef = useContext17(PanoramaViewContext);
|
|
7521
|
+
const eventBus = useContext17(PanoEventBusContext);
|
|
4913
7522
|
const { gl } = useThree9();
|
|
4914
7523
|
const [internallyDisabled, setInternallyDisabled] = useState6(false);
|
|
4915
|
-
const availableRef =
|
|
4916
|
-
const availabilityReportedRef =
|
|
4917
|
-
const activeRef =
|
|
4918
|
-
const permissionRef =
|
|
4919
|
-
const absoluteEventSourceRef =
|
|
4920
|
-
const rawQuaternionRef =
|
|
4921
|
-
const calibrationRef =
|
|
4922
|
-
const absoluteOffsetRef =
|
|
4923
|
-
const screenAngleRef =
|
|
4924
|
-
const startPoseRef =
|
|
4925
|
-
const enabledAtRef =
|
|
4926
|
-
const filteredPoseRef =
|
|
4927
|
-
const lastAppliedPoseRef =
|
|
4928
|
-
const callbacksRef =
|
|
7524
|
+
const availableRef = useRef14(false);
|
|
7525
|
+
const availabilityReportedRef = useRef14(null);
|
|
7526
|
+
const activeRef = useRef14(false);
|
|
7527
|
+
const permissionRef = useRef14(deviceOrientationPermissionState);
|
|
7528
|
+
const absoluteEventSourceRef = useRef14(null);
|
|
7529
|
+
const rawQuaternionRef = useRef14(null);
|
|
7530
|
+
const calibrationRef = useRef14(null);
|
|
7531
|
+
const absoluteOffsetRef = useRef14({ yaw: 0, pitch: 0 });
|
|
7532
|
+
const screenAngleRef = useRef14(getScreenOrientationAngle());
|
|
7533
|
+
const startPoseRef = useRef14(null);
|
|
7534
|
+
const enabledAtRef = useRef14(0);
|
|
7535
|
+
const filteredPoseRef = useRef14(null);
|
|
7536
|
+
const lastAppliedPoseRef = useRef14(null);
|
|
7537
|
+
const callbacksRef = useRef14({
|
|
4929
7538
|
onAvailable,
|
|
4930
7539
|
onUnavailable,
|
|
4931
7540
|
onEnable,
|
|
@@ -5070,22 +7679,22 @@ var Gyro = forwardRef3(function Gyro2({
|
|
|
5070
7679
|
}),
|
|
5071
7680
|
[requestPermission, resetSensor]
|
|
5072
7681
|
);
|
|
5073
|
-
|
|
7682
|
+
useEffect15(() => {
|
|
5074
7683
|
if (!enabled) {
|
|
5075
7684
|
setInternallyDisabled(false);
|
|
5076
7685
|
}
|
|
5077
7686
|
}, [enabled]);
|
|
5078
|
-
|
|
7687
|
+
useEffect15(() => {
|
|
5079
7688
|
const supported = typeof window !== "undefined" && window.isSecureContext && typeof DeviceOrientationEvent !== "undefined" && (desktopSupport || isMobileDevice());
|
|
5080
7689
|
setAvailable(supported);
|
|
5081
7690
|
return () => {
|
|
5082
7691
|
availableRef.current = false;
|
|
5083
7692
|
};
|
|
5084
7693
|
}, [desktopSupport, setAvailable]);
|
|
5085
|
-
|
|
7694
|
+
useEffect15(() => {
|
|
5086
7695
|
controlsRef.current?.setGyroTouchMode(touchMode);
|
|
5087
7696
|
}, [controlsRef, touchMode]);
|
|
5088
|
-
|
|
7697
|
+
useEffect15(() => {
|
|
5089
7698
|
if (!enabled || internallyDisabled || touchMode !== "disablegyro") {
|
|
5090
7699
|
return;
|
|
5091
7700
|
}
|
|
@@ -5099,7 +7708,7 @@ var Gyro = forwardRef3(function Gyro2({
|
|
|
5099
7708
|
gl.domElement.removeEventListener("pointerdown", onPointerDown);
|
|
5100
7709
|
};
|
|
5101
7710
|
}, [enabled, gl, internallyDisabled, touchMode]);
|
|
5102
|
-
|
|
7711
|
+
useEffect15(() => {
|
|
5103
7712
|
if (!enabled || internallyDisabled || !availableRef.current) {
|
|
5104
7713
|
deactivate();
|
|
5105
7714
|
return;
|
|
@@ -5264,11 +7873,11 @@ import { useThree as useThree12 } from "@react-three/fiber";
|
|
|
5264
7873
|
import {
|
|
5265
7874
|
forwardRef as forwardRef4,
|
|
5266
7875
|
useCallback as useCallback8,
|
|
5267
|
-
useContext as
|
|
5268
|
-
useEffect as
|
|
7876
|
+
useContext as useContext19,
|
|
7877
|
+
useEffect as useEffect19,
|
|
5269
7878
|
useImperativeHandle as useImperativeHandle4,
|
|
5270
7879
|
useMemo as useMemo10,
|
|
5271
|
-
useRef as
|
|
7880
|
+
useRef as useRef18,
|
|
5272
7881
|
useState as useState7
|
|
5273
7882
|
} from "react";
|
|
5274
7883
|
|
|
@@ -5293,12 +7902,12 @@ async function detectWebVRCapabilities() {
|
|
|
5293
7902
|
|
|
5294
7903
|
// src/webvr/reticle.tsx
|
|
5295
7904
|
import { useFrame as useFrame7, useThree as useThree10 } from "@react-three/fiber";
|
|
5296
|
-
import { useRef as
|
|
7905
|
+
import { useRef as useRef15 } from "react";
|
|
5297
7906
|
import {
|
|
5298
7907
|
DoubleSide,
|
|
5299
7908
|
Raycaster as Raycaster2,
|
|
5300
7909
|
Vector2 as Vector22,
|
|
5301
|
-
Vector3 as
|
|
7910
|
+
Vector3 as Vector37
|
|
5302
7911
|
} from "three";
|
|
5303
7912
|
import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
5304
7913
|
var CENTER_NDC = new Vector22(0, 0);
|
|
@@ -5384,13 +7993,13 @@ function WebVRReticle({
|
|
|
5384
7993
|
dwellMs,
|
|
5385
7994
|
visible
|
|
5386
7995
|
}) {
|
|
5387
|
-
const groupRef =
|
|
5388
|
-
const ringMeshRef =
|
|
5389
|
-
const directionRef =
|
|
5390
|
-
const raycasterRef =
|
|
5391
|
-
const hoveredRef =
|
|
5392
|
-
const dwellRef =
|
|
5393
|
-
const clickedRef =
|
|
7996
|
+
const groupRef = useRef15(null);
|
|
7997
|
+
const ringMeshRef = useRef15(null);
|
|
7998
|
+
const directionRef = useRef15(new Vector37());
|
|
7999
|
+
const raycasterRef = useRef15(new Raycaster2());
|
|
8000
|
+
const hoveredRef = useRef15(null);
|
|
8001
|
+
const dwellRef = useRef15(0);
|
|
8002
|
+
const clickedRef = useRef15(false);
|
|
5394
8003
|
const { camera, gl, scene } = useThree10();
|
|
5395
8004
|
useFrame7((_, deltaSeconds) => {
|
|
5396
8005
|
const group = groupRef.current;
|
|
@@ -5553,7 +8162,7 @@ function WebVRReticle({
|
|
|
5553
8162
|
|
|
5554
8163
|
// src/webvr/stereo.tsx
|
|
5555
8164
|
import { useFrame as useFrame8, useThree as useThree11 } from "@react-three/fiber";
|
|
5556
|
-
import { useContext as
|
|
8165
|
+
import { useContext as useContext18, useEffect as useEffect16, useMemo as useMemo9, useRef as useRef16 } from "react";
|
|
5557
8166
|
import {
|
|
5558
8167
|
Mesh as Mesh2,
|
|
5559
8168
|
OrthographicCamera,
|
|
@@ -5639,25 +8248,25 @@ function WebVRStereoRenderer({
|
|
|
5639
8248
|
screensize
|
|
5640
8249
|
}) {
|
|
5641
8250
|
const { camera, gl } = useThree11();
|
|
5642
|
-
const runtime =
|
|
5643
|
-
const fallbackStereoRef =
|
|
8251
|
+
const runtime = useContext18(WebVRRuntimeContext);
|
|
8252
|
+
const fallbackStereoRef = useRef16(null);
|
|
5644
8253
|
if (!fallbackStereoRef.current) {
|
|
5645
8254
|
fallbackStereoRef.current = new StereoCamera2();
|
|
5646
8255
|
}
|
|
5647
8256
|
const stereo = runtime?.stereoView.stereo ?? fallbackStereoRef.current;
|
|
5648
|
-
const stereoRef =
|
|
8257
|
+
const stereoRef = useRef16(stereo);
|
|
5649
8258
|
stereoRef.current = stereo;
|
|
5650
8259
|
const resources = useMemo9(createDistortionResources, []);
|
|
5651
|
-
const drawingSizeRef =
|
|
5652
|
-
const viewportRef =
|
|
5653
|
-
const scissorRef =
|
|
5654
|
-
const originalFovRef =
|
|
5655
|
-
const stereoActiveRef =
|
|
5656
|
-
const profileRef =
|
|
5657
|
-
const screensizeRef =
|
|
8260
|
+
const drawingSizeRef = useRef16(new Vector23());
|
|
8261
|
+
const viewportRef = useRef16(new Vector4());
|
|
8262
|
+
const scissorRef = useRef16(new Vector4());
|
|
8263
|
+
const originalFovRef = useRef16(null);
|
|
8264
|
+
const stereoActiveRef = useRef16(false);
|
|
8265
|
+
const profileRef = useRef16(profile);
|
|
8266
|
+
const screensizeRef = useRef16(screensize);
|
|
5658
8267
|
profileRef.current = profile;
|
|
5659
8268
|
screensizeRef.current = screensize;
|
|
5660
|
-
|
|
8269
|
+
useEffect16(
|
|
5661
8270
|
() => () => {
|
|
5662
8271
|
resources.geometry.dispose();
|
|
5663
8272
|
resources.material.dispose();
|
|
@@ -5665,7 +8274,7 @@ function WebVRStereoRenderer({
|
|
|
5665
8274
|
},
|
|
5666
8275
|
[resources]
|
|
5667
8276
|
);
|
|
5668
|
-
|
|
8277
|
+
useEffect16(() => {
|
|
5669
8278
|
const originalRender = gl.render.bind(gl);
|
|
5670
8279
|
gl.render = (sceneToRender, cameraToRender) => {
|
|
5671
8280
|
if (!stereoActiveRef.current || !(cameraToRender instanceof PerspectiveCamera2)) {
|
|
@@ -5729,7 +8338,7 @@ function WebVRStereoRenderer({
|
|
|
5729
8338
|
gl.render = originalRender;
|
|
5730
8339
|
};
|
|
5731
8340
|
}, [gl, resources]);
|
|
5732
|
-
|
|
8341
|
+
useEffect16(
|
|
5733
8342
|
() => () => {
|
|
5734
8343
|
if (runtime) {
|
|
5735
8344
|
runtime.stereoView.active = false;
|
|
@@ -5764,7 +8373,7 @@ function WebVRStereoRenderer({
|
|
|
5764
8373
|
}
|
|
5765
8374
|
|
|
5766
8375
|
// src/webvr/pointerlock.ts
|
|
5767
|
-
import { useEffect as
|
|
8376
|
+
import { useEffect as useEffect17, useRef as useRef17 } from "react";
|
|
5768
8377
|
var POINTER_LOCK_CURSOR_ID = "webvr:pointerlock";
|
|
5769
8378
|
async function requestWebVRPointerLock(element) {
|
|
5770
8379
|
if (typeof document === "undefined") {
|
|
@@ -5797,11 +8406,11 @@ function exitWebVRPointerLock(element) {
|
|
|
5797
8406
|
}
|
|
5798
8407
|
function useWebVRPointerLock(enabled, element) {
|
|
5799
8408
|
const cursor = usePanoCursor();
|
|
5800
|
-
const cursorRef =
|
|
5801
|
-
const enabledRef =
|
|
8409
|
+
const cursorRef = useRef17(cursor);
|
|
8410
|
+
const enabledRef = useRef17(enabled);
|
|
5802
8411
|
cursorRef.current = cursor;
|
|
5803
8412
|
enabledRef.current = enabled;
|
|
5804
|
-
|
|
8413
|
+
useEffect17(() => {
|
|
5805
8414
|
if (!enabled || !element) {
|
|
5806
8415
|
return;
|
|
5807
8416
|
}
|
|
@@ -5831,7 +8440,7 @@ function useWebVRPointerLock(enabled, element) {
|
|
|
5831
8440
|
}
|
|
5832
8441
|
|
|
5833
8442
|
// src/webvr/wakelock.ts
|
|
5834
|
-
import { useEffect as
|
|
8443
|
+
import { useEffect as useEffect18 } from "react";
|
|
5835
8444
|
|
|
5836
8445
|
// src/webvr/wakelock-fallback.ts
|
|
5837
8446
|
var WEBVR_WAKELOCK_FALLBACK_VIDEO_BASE64 = "AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAAbBbW9vdgAAAGxtdmhkAAAAAAAAAAAAAAAAAAAD6AAAD4AAAQAAAQAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAxt0cmFrAAAAXHRraGQAAAADAAAAAAAAAAAAAAABAAAAAAAAAggAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAABAAAAAQAAAAAAAkZWR0cwAAABxlbHN0AAAAAAAAAAEAAAIIAAAEAAABAAAAAAKTbWRpYQAAACBtZGhkAAAAAAAAAAAAAAAAAAAyAAAAGgBVxAAAAAAALWhkbHIAAAAAAAAAAHZpZGUAAAAAAAAAAAAAAABWaWRlb0hhbmRsZXIAAAACPm1pbmYAAAAUdm1oZAAAAAEAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAf5zdGJsAAAAvnN0c2QAAAAAAAAAAQAAAK5hdmMxAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAABAAEABIAAAASAAAAAAAAAABFUxhdmM2Mi4xMS4xMDAgbGlieDI2NAAAAAAAAAAAAAAAGP//AAAANGF2Y0MBZAAK/+EAF2dkAAqs2V7ARAAAAwAEAAADAMg8SJZYAQAGaOvjyyLA/fj4AAAAABBwYXNwAAAAAQAAAAEAAAAUYnRydAAAAAAAADQ5AAAAAAAAABhzdHRzAAAAAAAAAAEAAAANAAACAAAAABRzdHNzAAAAAAAAAAEAAAABAAAAeGN0dHMAAAAAAAAADQAAAAEAAAQAAAAAAQAACgAAAAABAAAEAAAAAAEAAAAAAAAAAQAAAgAAAAABAAAKAAAAAAEAAAQAAAAAAQAAAAAAAAABAAACAAAAAAEAAAoAAAAAAQAABAAAAAABAAAAAAAAAAEAAAIAAAAAKHN0c2MAAAAAAAAAAgAAAAEAAAADAAAAAQAAAAUAAAABAAAAAQAAAEhzdHN6AAAAAAAAAAAAAAANAAACxQAAAAwAAAAMAAAADAAAAAwAAAASAAAADgAAAAwAAAAMAAAAEgAAAA4AAAAMAAAADAAAACRzdGNvAAAAAAAAAAUAAAcGAAAJ5wAAChUAAAo/AAAKbwAAAtF0cmFrAAAAXHRraGQAAAADAAAAAAAAAAAAAAACAAAAAAAAD4AAAAAAAAAAAAAAAAEBAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAkZWR0cwAAABxlbHN0AAAAAAAAAAEAAA+AAAAEAAABAAAAAAJJbWRpYQAAACBtZGhkAAAAAAAAAAAAAAAAAAAfQAAAgABVxAAAAAAALWhkbHIAAAAAAAAAAHNvdW4AAAAAAAAAAAAAAABTb3VuZEhhbmRsZXIAAAAB9G1pbmYAAAAQc21oZAAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAABuHN0YmwAAAB+c3RzZAAAAAAAAAABAAAAbm1wNGEAAAAAAAAAAQAAAAAAAAAAAAEAEAAAAAAfQAAAAAAANmVzZHMAAAAAA4CAgCUAAgAEgICAF0AVAAAAAAAfQAAAARsFgICABRWIVuUABoCAgAECAAAAFGJ0cnQAAAAAAAAfQAAAARsAAAAYc3R0cwAAAAAAAAABAAAAIAAABAAAAAAoc3RzYwAAAAAAAAACAAAAAQAAAAEAAAABAAAABgAAABsAAAABAAAAlHN0c3oAAAAAAAAAAAAAACAAAAAVAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAABAAAAChzdGNvAAAAAAAAAAYAAAbxAAAJ4wAAChEAAAo7AAAKawAACnsAAAAac2dwZAEAAAByb2xsAAAAAgAAAAH//wAAABxzYmdwAAAAAHJvbGwAAAABAAAAIAAAAAEAAABhdWR0YQAAAFltZXRhAAAAAAAAACFoZGxyAAAAAAAAAABtZGlyYXBwbAAAAAAAAAAAAAAAACxpbHN0AAAAJKl0b28AAAAcZGF0YQAAAAEAAAAATGF2ZjYyLjMuMTAwAAAACGZyZWUAAAP+bWRhdN4CAExhdmM2Mi4xMS4xMDAAAjBADgAAAq4GBf//qtxF6b3m2Ui3lizYINkj7u94MjY0IC0gY29yZSAxNjUgcjMyMjIgYjM1NjA1YSAtIEguMjY0L01QRUctNCBBVkMgY29kZWMgLSBDb3B5bGVmdCAyMDAzLTIwMjUgLSBodHRwOi8vd3d3LnZpZGVvbGFuLm9yZy94MjY0Lmh0bWwgLSBvcHRpb25zOiBjYWJhYz0xIHJlZj0zIGRlYmxvY2s9MTowOjAgYW5hbHlzZT0weDM6MHgxMTMgbWU9aGV4IHN1Ym1lPTcgcHN5PTEgcHN5X3JkPTEuMDA6MC4wMCBtaXhlZF9yZWY9MSBtZV9yYW5nZT0xNiBjaHJvbWFfbWU9MSB0cmVsbGlzPTEgOHg4ZGN0PTEgY3FtPTAgZGVhZHpvbmU9MjEsMTEgZmFzdF9wc2tpcD0xIGNocm9tYV9xcF9vZmZzZXQ9LTIgdGhyZWFkcz0xIGxvb2thaGVhZF90aHJlYWRzPTEgc2xpY2VkX3RocmVhZHM9MCBucj0wIGRlY2ltYXRlPTEgaW50ZXJsYWNlZD0wIGJsdXJheV9jb21wYXQ9MCBjb25zdHJhaW5lZF9pbnRyYT0wIGJmcmFtZXM9MyBiX3B5cmFtaWQ9MiBiX2FkYXB0PTEgYl9iaWFzPTAgZGlyZWN0PTEgd2VpZ2h0Yj0xIG9wZW5fZ29wPTAgd2VpZ2h0cD0yIGtleWludD0yNTAga2V5aW50X21pbj0yNSBzY2VuZWN1dD00MCBpbnRyYV9yZWZyZXNoPTAgcmNfbG9va2FoZWFkPTQwIHJjPWNyZiBtYnRyZWU9MSBjcmY9MjMuMCBxY29tcD0wLjYwIHFwbWluPTAgcXBtYXg9NjkgcXBzdGVwPTQgaXBfcmF0aW89MS40MCBhcT0xOjEuMDAAgAAAAA9liIQAO//+906/AptUwmEAAAAIQZokbEN//uAAAAAIQZ5CeIX/wYEBGCAHAAAACAGeYXRCv8SAAAAACAGeY2pCv8SBAAAADkGaaEmoQWiZTAhn//7hARggBwAAAApBnoZFESwv/8GBAAAACAGepXRCv8SBAAAACAGep2pCv8SAARggBwAAAA5BmqxJqEFsmUwIV//+wAAAAApBnspFFSwv/8GBAAAACAGe6XRCv8SAARggBwAAAAgBnutqQr/EgAEYIAcBGCAHARggBwEYIAcBGCAHARggBwEYIAcBGCAHARggBwEYIAcBGCAHARggBwEYIAcBGCAHARggBwEYIAcBGCAHARggBwEYIAcBGCAHARggBwEYIAcBGCAHARggBwEYIAcBGCAHARggBw==";
|
|
@@ -5965,7 +8574,7 @@ function releaseWebVRWakeLock() {
|
|
|
5965
8574
|
stopFallbackVideo();
|
|
5966
8575
|
}
|
|
5967
8576
|
function useWebVRWakeLock(enabled) {
|
|
5968
|
-
|
|
8577
|
+
useEffect18(() => {
|
|
5969
8578
|
if (!enabled) {
|
|
5970
8579
|
return;
|
|
5971
8580
|
}
|
|
@@ -6013,24 +8622,24 @@ var WebVR = forwardRef4(function WebVR2({
|
|
|
6013
8622
|
onDenied,
|
|
6014
8623
|
onUnknownDevice
|
|
6015
8624
|
}, ref) {
|
|
6016
|
-
const runtime =
|
|
6017
|
-
const controlsRef =
|
|
6018
|
-
const eventBus =
|
|
8625
|
+
const runtime = useContext19(WebVRRuntimeContext);
|
|
8626
|
+
const controlsRef = useContext19(PanoramaViewContext);
|
|
8627
|
+
const eventBus = useContext19(PanoEventBusContext);
|
|
6019
8628
|
const gl = useThree12((state) => state.gl);
|
|
6020
|
-
const gyroRef =
|
|
6021
|
-
const capabilitiesRef =
|
|
8629
|
+
const gyroRef = useRef18(null);
|
|
8630
|
+
const capabilitiesRef = useRef18({
|
|
6022
8631
|
mobile: false,
|
|
6023
8632
|
sensor: false,
|
|
6024
8633
|
webxr: false
|
|
6025
8634
|
});
|
|
6026
|
-
const availableRef =
|
|
6027
|
-
const modeRef =
|
|
6028
|
-
const webXRSessionRef =
|
|
8635
|
+
const availableRef = useRef18(false);
|
|
8636
|
+
const modeRef = useRef18(null);
|
|
8637
|
+
const webXRSessionRef = useRef18(null);
|
|
6029
8638
|
const [mode, setMode] = useState7(null);
|
|
6030
8639
|
const [settings, setSettings] = useState7(
|
|
6031
8640
|
() => initializeSettings(screensize, profile)
|
|
6032
8641
|
);
|
|
6033
|
-
const callbacksRef =
|
|
8642
|
+
const callbacksRef = useRef18({
|
|
6034
8643
|
onAvailable,
|
|
6035
8644
|
onDenied,
|
|
6036
8645
|
onEnterVR,
|
|
@@ -6239,7 +8848,7 @@ var WebVR = forwardRef4(function WebVR2({
|
|
|
6239
8848
|
}),
|
|
6240
8849
|
[enterVR, exitVR, requestPermission, toggleVR]
|
|
6241
8850
|
);
|
|
6242
|
-
|
|
8851
|
+
useEffect19(() => {
|
|
6243
8852
|
let active = true;
|
|
6244
8853
|
void detectWebVRCapabilities().then((capabilities) => {
|
|
6245
8854
|
if (!active) {
|
|
@@ -6261,7 +8870,7 @@ var WebVR = forwardRef4(function WebVR2({
|
|
|
6261
8870
|
active = false;
|
|
6262
8871
|
};
|
|
6263
8872
|
}, [desktopSupport, eventBus, fakeSupport, host, mobileVr]);
|
|
6264
|
-
|
|
8873
|
+
useEffect19(() => {
|
|
6265
8874
|
host.controller = controller;
|
|
6266
8875
|
return () => {
|
|
6267
8876
|
if (host.controller === controller) {
|
|
@@ -6270,10 +8879,10 @@ var WebVR = forwardRef4(function WebVR2({
|
|
|
6270
8879
|
}
|
|
6271
8880
|
};
|
|
6272
8881
|
}, [controller, host]);
|
|
6273
|
-
|
|
8882
|
+
useEffect19(() => {
|
|
6274
8883
|
updateWebVRHost(host, { chrome, mode, settings });
|
|
6275
8884
|
}, [chrome, host, mode, settings]);
|
|
6276
|
-
|
|
8885
|
+
useEffect19(() => {
|
|
6277
8886
|
if (mode !== "fake") {
|
|
6278
8887
|
return;
|
|
6279
8888
|
}
|
|
@@ -6297,7 +8906,7 @@ var WebVR = forwardRef4(function WebVR2({
|
|
|
6297
8906
|
document.removeEventListener("mousemove", onMouseMove);
|
|
6298
8907
|
};
|
|
6299
8908
|
}, [controlsRef, gl.domElement, mode, mousePointerLock]);
|
|
6300
|
-
|
|
8909
|
+
useEffect19(
|
|
6301
8910
|
() => () => {
|
|
6302
8911
|
const session2 = webXRSessionRef.current;
|
|
6303
8912
|
if (session2) {
|
|
@@ -6351,12 +8960,12 @@ var WebVR = forwardRef4(function WebVR2({
|
|
|
6351
8960
|
|
|
6352
8961
|
// src/sphere.tsx
|
|
6353
8962
|
import { useThree as useThree13 } from "@react-three/fiber";
|
|
6354
|
-
import { useEffect as
|
|
8963
|
+
import { useEffect as useEffect20, useMemo as useMemo12, useRef as useRef20, useState as useState8 } from "react";
|
|
6355
8964
|
import {
|
|
6356
8965
|
BackSide as BackSide2,
|
|
6357
8966
|
LinearFilter,
|
|
6358
8967
|
LinearMipmapLinearFilter,
|
|
6359
|
-
MathUtils as
|
|
8968
|
+
MathUtils as MathUtils5,
|
|
6360
8969
|
RepeatWrapping,
|
|
6361
8970
|
SRGBColorSpace,
|
|
6362
8971
|
TextureLoader
|
|
@@ -6384,7 +8993,7 @@ function resolveUrlAgainstFile(fileUrl, path) {
|
|
|
6384
8993
|
}
|
|
6385
8994
|
|
|
6386
8995
|
// src/pano-filter/pano-basic-material.tsx
|
|
6387
|
-
import { useLayoutEffect as useLayoutEffect2, useMemo as useMemo11, useRef as
|
|
8996
|
+
import { useLayoutEffect as useLayoutEffect2, useMemo as useMemo11, useRef as useRef19 } from "react";
|
|
6388
8997
|
|
|
6389
8998
|
// src/pano-filter/shaders.ts
|
|
6390
8999
|
var GLSL_FILTER_COMMON = `
|
|
@@ -6544,9 +9153,9 @@ function PanoBasicMaterial({
|
|
|
6544
9153
|
toneMapped = false
|
|
6545
9154
|
}) {
|
|
6546
9155
|
const snapshot = usePanoFilterSnapshot();
|
|
6547
|
-
const materialRef =
|
|
6548
|
-
const intensityRef =
|
|
6549
|
-
const intensityUniformRef =
|
|
9156
|
+
const materialRef = useRef19(null);
|
|
9157
|
+
const intensityRef = useRef19(snapshot.intensity);
|
|
9158
|
+
const intensityUniformRef = useRef19(null);
|
|
6550
9159
|
intensityRef.current = snapshot.intensity;
|
|
6551
9160
|
const active = isPanoFilterActive(snapshot);
|
|
6552
9161
|
const preset = snapshot.preset;
|
|
@@ -6601,11 +9210,11 @@ function PanoBasicMaterial({
|
|
|
6601
9210
|
import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
6602
9211
|
function useEquirectTexture(url, anisotropy, generateMipmaps, onLoad, onError) {
|
|
6603
9212
|
const [texture, setTexture] = useState8(null);
|
|
6604
|
-
const onLoadRef =
|
|
6605
|
-
const onErrorRef =
|
|
9213
|
+
const onLoadRef = useRef20(onLoad);
|
|
9214
|
+
const onErrorRef = useRef20(onError);
|
|
6606
9215
|
onLoadRef.current = onLoad;
|
|
6607
9216
|
onErrorRef.current = onError;
|
|
6608
|
-
|
|
9217
|
+
useEffect20(() => {
|
|
6609
9218
|
if (!url) {
|
|
6610
9219
|
setTexture(null);
|
|
6611
9220
|
return;
|
|
@@ -6644,7 +9253,7 @@ function useEquirectTexture(url, anisotropy, generateMipmaps, onLoad, onError) {
|
|
|
6644
9253
|
active = false;
|
|
6645
9254
|
};
|
|
6646
9255
|
}, [anisotropy, generateMipmaps, url]);
|
|
6647
|
-
|
|
9256
|
+
useEffect20(
|
|
6648
9257
|
() => () => {
|
|
6649
9258
|
texture?.dispose();
|
|
6650
9259
|
},
|
|
@@ -6683,11 +9292,11 @@ function Sphere({
|
|
|
6683
9292
|
onPreviewError
|
|
6684
9293
|
);
|
|
6685
9294
|
const displayTexture = texture ?? previewTexture;
|
|
6686
|
-
const readyRef =
|
|
6687
|
-
|
|
9295
|
+
const readyRef = useRef20(false);
|
|
9296
|
+
useEffect20(() => {
|
|
6688
9297
|
readyRef.current = false;
|
|
6689
9298
|
}, [resolvedPreviewUrl, src]);
|
|
6690
|
-
|
|
9299
|
+
useEffect20(() => {
|
|
6691
9300
|
if (!displayTexture || readyRef.current) {
|
|
6692
9301
|
return;
|
|
6693
9302
|
}
|
|
@@ -6700,7 +9309,7 @@ function Sphere({
|
|
|
6700
9309
|
return /* @__PURE__ */ jsxs9(
|
|
6701
9310
|
"mesh",
|
|
6702
9311
|
{
|
|
6703
|
-
rotation: [0,
|
|
9312
|
+
rotation: [0, MathUtils5.degToRad(90 + yawOffset), 0],
|
|
6704
9313
|
visible,
|
|
6705
9314
|
children: [
|
|
6706
9315
|
/* @__PURE__ */ jsx15("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
|
|
@@ -6721,18 +9330,18 @@ function Sphere({
|
|
|
6721
9330
|
import { useThree as useThree14 } from "@react-three/fiber";
|
|
6722
9331
|
import {
|
|
6723
9332
|
useCallback as useCallback9,
|
|
6724
|
-
useContext as
|
|
6725
|
-
useEffect as
|
|
9333
|
+
useContext as useContext20,
|
|
9334
|
+
useEffect as useEffect21,
|
|
6726
9335
|
useLayoutEffect as useLayoutEffect3,
|
|
6727
9336
|
useMemo as useMemo13,
|
|
6728
|
-
useRef as
|
|
9337
|
+
useRef as useRef21,
|
|
6729
9338
|
useState as useState9
|
|
6730
9339
|
} from "react";
|
|
6731
9340
|
import {
|
|
6732
9341
|
BackSide as BackSide3,
|
|
6733
9342
|
LinearFilter as LinearFilter2,
|
|
6734
9343
|
LinearMipmapLinearFilter as LinearMipmapLinearFilter2,
|
|
6735
|
-
MathUtils as
|
|
9344
|
+
MathUtils as MathUtils6,
|
|
6736
9345
|
RepeatWrapping as RepeatWrapping2,
|
|
6737
9346
|
SRGBColorSpace as SRGBColorSpace2,
|
|
6738
9347
|
TextureLoader as TextureLoader2,
|
|
@@ -6824,9 +9433,9 @@ function applyEquirectangularLayout(texture, anisotropy) {
|
|
|
6824
9433
|
function usePosterTexture(poster, onError) {
|
|
6825
9434
|
const gl = useThree14((state) => state.gl);
|
|
6826
9435
|
const [texture, setTexture] = useState9(null);
|
|
6827
|
-
const onErrorRef =
|
|
9436
|
+
const onErrorRef = useRef21(onError);
|
|
6828
9437
|
onErrorRef.current = onError;
|
|
6829
|
-
|
|
9438
|
+
useEffect21(() => {
|
|
6830
9439
|
let active = true;
|
|
6831
9440
|
setTexture(null);
|
|
6832
9441
|
if (!poster) {
|
|
@@ -6863,7 +9472,7 @@ function usePosterTexture(poster, onError) {
|
|
|
6863
9472
|
active = false;
|
|
6864
9473
|
};
|
|
6865
9474
|
}, [gl, poster]);
|
|
6866
|
-
|
|
9475
|
+
useEffect21(
|
|
6867
9476
|
() => () => {
|
|
6868
9477
|
texture?.dispose();
|
|
6869
9478
|
},
|
|
@@ -6921,8 +9530,8 @@ function PanoVideo({
|
|
|
6921
9530
|
onTrackChange
|
|
6922
9531
|
}) {
|
|
6923
9532
|
const gl = useThree14((state) => state.gl);
|
|
6924
|
-
const host =
|
|
6925
|
-
const overlay =
|
|
9533
|
+
const host = useContext20(PanoVideoHostContext);
|
|
9534
|
+
const overlay = useContext20(PanoChromeOverlayContext);
|
|
6926
9535
|
const variants = useMemo13(
|
|
6927
9536
|
() => resolvePanoVideoVariants({ poster, src, variants: variantsProp }),
|
|
6928
9537
|
[poster, src, variantsProp]
|
|
@@ -6942,17 +9551,17 @@ function PanoVideo({
|
|
|
6942
9551
|
() => captionsEnabled ? defaultPanoVideoTrackId(tracks) : null
|
|
6943
9552
|
);
|
|
6944
9553
|
const [ready, setReady] = useState9(false);
|
|
6945
|
-
const autoPlayRef =
|
|
9554
|
+
const autoPlayRef = useRef21(autoPlay);
|
|
6946
9555
|
autoPlayRef.current = autoPlay;
|
|
6947
|
-
const blockedRef =
|
|
6948
|
-
const captionAppearanceOverrideRef =
|
|
9556
|
+
const blockedRef = useRef21(false);
|
|
9557
|
+
const captionAppearanceOverrideRef = useRef21(
|
|
6949
9558
|
{}
|
|
6950
9559
|
);
|
|
6951
|
-
const mediaCapabilitiesRef =
|
|
9560
|
+
const mediaCapabilitiesRef = useRef21({
|
|
6952
9561
|
volumeAdjustable: true,
|
|
6953
9562
|
playbackRates: [...DEFAULT_PANO_VIDEO_PLAYBACK_RATES]
|
|
6954
9563
|
});
|
|
6955
|
-
const storeRef =
|
|
9564
|
+
const storeRef = useRef21(null);
|
|
6956
9565
|
if (!storeRef.current) {
|
|
6957
9566
|
storeRef.current = {
|
|
6958
9567
|
snapshot: {
|
|
@@ -6962,7 +9571,7 @@ function PanoVideo({
|
|
|
6962
9571
|
listeners: /* @__PURE__ */ new Set()
|
|
6963
9572
|
};
|
|
6964
9573
|
}
|
|
6965
|
-
const actionsRef =
|
|
9574
|
+
const actionsRef = useRef21({
|
|
6966
9575
|
play: async () => {
|
|
6967
9576
|
},
|
|
6968
9577
|
pause: () => {
|
|
@@ -6982,12 +9591,12 @@ function PanoVideo({
|
|
|
6982
9591
|
setCaptionAppearance: (_appearance) => {
|
|
6983
9592
|
}
|
|
6984
9593
|
});
|
|
6985
|
-
const onLoadRef =
|
|
6986
|
-
const onErrorRef =
|
|
6987
|
-
const onPlaybackStateChangeRef =
|
|
6988
|
-
const onEndedRef =
|
|
6989
|
-
const onVariantChangeRef =
|
|
6990
|
-
const onTrackChangeRef =
|
|
9594
|
+
const onLoadRef = useRef21(onLoad);
|
|
9595
|
+
const onErrorRef = useRef21(onError);
|
|
9596
|
+
const onPlaybackStateChangeRef = useRef21(onPlaybackStateChange);
|
|
9597
|
+
const onEndedRef = useRef21(onEnded);
|
|
9598
|
+
const onVariantChangeRef = useRef21(onVariantChange);
|
|
9599
|
+
const onTrackChangeRef = useRef21(onTrackChange);
|
|
6991
9600
|
onLoadRef.current = onLoad;
|
|
6992
9601
|
onErrorRef.current = onError;
|
|
6993
9602
|
onPlaybackStateChangeRef.current = onPlaybackStateChange;
|
|
@@ -7011,7 +9620,7 @@ function PanoVideo({
|
|
|
7011
9620
|
texture.generateMipmaps = false;
|
|
7012
9621
|
return { video, texture };
|
|
7013
9622
|
}, []);
|
|
7014
|
-
|
|
9623
|
+
useEffect21(
|
|
7015
9624
|
() => () => {
|
|
7016
9625
|
if (!resource) {
|
|
7017
9626
|
return;
|
|
@@ -7026,13 +9635,13 @@ function PanoVideo({
|
|
|
7026
9635
|
},
|
|
7027
9636
|
[resource]
|
|
7028
9637
|
);
|
|
7029
|
-
|
|
9638
|
+
useEffect21(() => {
|
|
7030
9639
|
if (!resource) {
|
|
7031
9640
|
return;
|
|
7032
9641
|
}
|
|
7033
9642
|
resource.texture.anisotropy = gl.capabilities.getMaxAnisotropy();
|
|
7034
9643
|
}, [gl, resource]);
|
|
7035
|
-
|
|
9644
|
+
useEffect21(() => {
|
|
7036
9645
|
if (!resource || !overlay?.overlayElement) {
|
|
7037
9646
|
return;
|
|
7038
9647
|
}
|
|
@@ -7185,10 +9794,10 @@ function PanoVideo({
|
|
|
7185
9794
|
};
|
|
7186
9795
|
emitSnapshot();
|
|
7187
9796
|
}, [emitSnapshot, playbackRates, resource]);
|
|
7188
|
-
|
|
9797
|
+
useEffect21(() => {
|
|
7189
9798
|
emitSnapshot();
|
|
7190
9799
|
}, [emitSnapshot]);
|
|
7191
|
-
|
|
9800
|
+
useEffect21(() => {
|
|
7192
9801
|
if (!resource || !activeVariant || !mediaKey) {
|
|
7193
9802
|
return;
|
|
7194
9803
|
}
|
|
@@ -7245,7 +9854,7 @@ function PanoVideo({
|
|
|
7245
9854
|
video.removeEventListener("error", handleError);
|
|
7246
9855
|
};
|
|
7247
9856
|
}, [mediaKey, resource]);
|
|
7248
|
-
|
|
9857
|
+
useEffect21(() => {
|
|
7249
9858
|
if (!resource) {
|
|
7250
9859
|
return;
|
|
7251
9860
|
}
|
|
@@ -7335,7 +9944,7 @@ function PanoVideo({
|
|
|
7335
9944
|
}
|
|
7336
9945
|
};
|
|
7337
9946
|
}, [emitSnapshot, resource]);
|
|
7338
|
-
|
|
9947
|
+
useEffect21(() => {
|
|
7339
9948
|
if (!resource) {
|
|
7340
9949
|
return;
|
|
7341
9950
|
}
|
|
@@ -7348,7 +9957,7 @@ function PanoVideo({
|
|
|
7348
9957
|
video.playsInline = playsInline;
|
|
7349
9958
|
video.preload = preload;
|
|
7350
9959
|
}, [loop, muted, playsInline, preload, resource, volume]);
|
|
7351
|
-
|
|
9960
|
+
useEffect21(() => {
|
|
7352
9961
|
if (!resource) {
|
|
7353
9962
|
return;
|
|
7354
9963
|
}
|
|
@@ -7398,7 +10007,7 @@ function PanoVideo({
|
|
|
7398
10007
|
video.removeEventListener("ratechange", handleVolume);
|
|
7399
10008
|
};
|
|
7400
10009
|
}, [emitSnapshot, resource]);
|
|
7401
|
-
|
|
10010
|
+
useEffect21(() => {
|
|
7402
10011
|
if (!resource) {
|
|
7403
10012
|
return;
|
|
7404
10013
|
}
|
|
@@ -7433,7 +10042,7 @@ function PanoVideo({
|
|
|
7433
10042
|
video.textTracks.removeEventListener("change", applyModes);
|
|
7434
10043
|
};
|
|
7435
10044
|
}, [emitSnapshot, resource, trackId, tracks]);
|
|
7436
|
-
|
|
10045
|
+
useEffect21(() => {
|
|
7437
10046
|
if (!captionsEnabled) {
|
|
7438
10047
|
setTrackId(null);
|
|
7439
10048
|
return;
|
|
@@ -7448,7 +10057,7 @@ function PanoVideo({
|
|
|
7448
10057
|
activeTexture ? /* @__PURE__ */ jsxs10(
|
|
7449
10058
|
"mesh",
|
|
7450
10059
|
{
|
|
7451
|
-
rotation: [0,
|
|
10060
|
+
rotation: [0, MathUtils6.degToRad(90 + yawOffset), 0],
|
|
7452
10061
|
visible,
|
|
7453
10062
|
children: [
|
|
7454
10063
|
/* @__PURE__ */ jsx16("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
|
|
@@ -7472,10 +10081,10 @@ import { useFrame as useFrame12, useThree as useThree19 } from "@react-three/fib
|
|
|
7472
10081
|
import {
|
|
7473
10082
|
Fragment as Fragment6,
|
|
7474
10083
|
useCallback as useCallback10,
|
|
7475
|
-
useContext as
|
|
7476
|
-
useEffect as
|
|
10084
|
+
useContext as useContext22,
|
|
10085
|
+
useEffect as useEffect26,
|
|
7477
10086
|
useMemo as useMemo18,
|
|
7478
|
-
useRef as
|
|
10087
|
+
useRef as useRef25,
|
|
7479
10088
|
useState as useState11
|
|
7480
10089
|
} from "react";
|
|
7481
10090
|
import {
|
|
@@ -7532,7 +10141,7 @@ function isSnapshotTransition(preset) {
|
|
|
7532
10141
|
|
|
7533
10142
|
// src/scene-transitions/particle-overlay.tsx
|
|
7534
10143
|
import { useFrame as useFrame9, useThree as useThree15 } from "@react-three/fiber";
|
|
7535
|
-
import { useEffect as
|
|
10144
|
+
import { useEffect as useEffect22, useMemo as useMemo14, useRef as useRef22 } from "react";
|
|
7536
10145
|
import {
|
|
7537
10146
|
DoubleSide as DoubleSide2,
|
|
7538
10147
|
InstancedBufferAttribute,
|
|
@@ -7540,7 +10149,7 @@ import {
|
|
|
7540
10149
|
PlaneGeometry as PlaneGeometry3,
|
|
7541
10150
|
ShaderMaterial as ShaderMaterial2,
|
|
7542
10151
|
Vector2 as Vector24,
|
|
7543
|
-
Vector3 as
|
|
10152
|
+
Vector3 as Vector39
|
|
7544
10153
|
} from "three";
|
|
7545
10154
|
|
|
7546
10155
|
// src/scene-transitions/glsl.ts
|
|
@@ -7672,10 +10281,10 @@ function ParticleOverlay({
|
|
|
7672
10281
|
onFinish
|
|
7673
10282
|
}) {
|
|
7674
10283
|
const { camera } = useThree15();
|
|
7675
|
-
const meshRef =
|
|
7676
|
-
const startRef =
|
|
7677
|
-
const finishedRef =
|
|
7678
|
-
const directionRef =
|
|
10284
|
+
const meshRef = useRef22(null);
|
|
10285
|
+
const startRef = useRef22(null);
|
|
10286
|
+
const finishedRef = useRef22(false);
|
|
10287
|
+
const directionRef = useRef22(new Vector39());
|
|
7679
10288
|
const geometry = useMemo14(() => createParticleGeometry(), []);
|
|
7680
10289
|
const material = useMemo14(
|
|
7681
10290
|
() => new ShaderMaterial2({
|
|
@@ -7693,9 +10302,9 @@ function ParticleOverlay({
|
|
|
7693
10302
|
}),
|
|
7694
10303
|
[snapshot.texture]
|
|
7695
10304
|
);
|
|
7696
|
-
|
|
7697
|
-
|
|
7698
|
-
|
|
10305
|
+
useEffect22(() => () => geometry.dispose(), [geometry]);
|
|
10306
|
+
useEffect22(() => () => material.dispose(), [material]);
|
|
10307
|
+
useEffect22(() => {
|
|
7699
10308
|
startRef.current = null;
|
|
7700
10309
|
finishedRef.current = false;
|
|
7701
10310
|
material.uniforms.progress.value = 0;
|
|
@@ -7731,8 +10340,8 @@ function ParticleOverlay({
|
|
|
7731
10340
|
|
|
7732
10341
|
// src/scene-transitions/snapshot-overlay.tsx
|
|
7733
10342
|
import { useFrame as useFrame10, useThree as useThree16 } from "@react-three/fiber";
|
|
7734
|
-
import { useEffect as
|
|
7735
|
-
import { Vector3 as
|
|
10343
|
+
import { useEffect as useEffect23, useMemo as useMemo15, useRef as useRef23 } from "react";
|
|
10344
|
+
import { Vector3 as Vector310 } from "three";
|
|
7736
10345
|
|
|
7737
10346
|
// src/scene-transitions/snapshot-shaders.ts
|
|
7738
10347
|
import { DoubleSide as DoubleSide3, ShaderMaterial as ShaderMaterial3, Vector2 as Vector25 } from "three";
|
|
@@ -8020,18 +10629,18 @@ function SnapshotOverlay({
|
|
|
8020
10629
|
onFinish
|
|
8021
10630
|
}) {
|
|
8022
10631
|
const { camera, gl } = useThree16();
|
|
8023
|
-
const meshRef =
|
|
8024
|
-
const startRef =
|
|
8025
|
-
const finishedRef =
|
|
8026
|
-
const directionRef =
|
|
10632
|
+
const meshRef = useRef23(null);
|
|
10633
|
+
const startRef = useRef23(null);
|
|
10634
|
+
const finishedRef = useRef23(false);
|
|
10635
|
+
const directionRef = useRef23(new Vector310());
|
|
8027
10636
|
const material = useMemo15(() => {
|
|
8028
10637
|
if (!isSnapshotTransition(transition.preset)) {
|
|
8029
10638
|
return null;
|
|
8030
10639
|
}
|
|
8031
10640
|
return createSnapshotMaterial(transition.preset, snapshot.texture);
|
|
8032
10641
|
}, [snapshot.texture, transition.preset]);
|
|
8033
|
-
|
|
8034
|
-
|
|
10642
|
+
useEffect23(() => () => material?.dispose(), [material]);
|
|
10643
|
+
useEffect23(() => {
|
|
8035
10644
|
startRef.current = null;
|
|
8036
10645
|
finishedRef.current = false;
|
|
8037
10646
|
if (material) {
|
|
@@ -8115,8 +10724,8 @@ function TransitionOverlay(props) {
|
|
|
8115
10724
|
import { useThree as useThree17 } from "@react-three/fiber";
|
|
8116
10725
|
import {
|
|
8117
10726
|
createContext as createContext11,
|
|
8118
|
-
useContext as
|
|
8119
|
-
useEffect as
|
|
10727
|
+
useContext as useContext21,
|
|
10728
|
+
useEffect as useEffect24,
|
|
8120
10729
|
useMemo as useMemo16
|
|
8121
10730
|
} from "react";
|
|
8122
10731
|
|
|
@@ -8367,23 +10976,23 @@ function TileTextureManagerProvider({
|
|
|
8367
10976
|
}),
|
|
8368
10977
|
[anisotropy, maxConcurrentLoads, maxTextureMemoryMb]
|
|
8369
10978
|
);
|
|
8370
|
-
|
|
10979
|
+
useEffect24(() => {
|
|
8371
10980
|
manager.resume();
|
|
8372
10981
|
return () => manager.dispose();
|
|
8373
10982
|
}, [manager]);
|
|
8374
10983
|
return /* @__PURE__ */ jsx20(TileTextureManagerContext.Provider, { value: manager, children });
|
|
8375
10984
|
}
|
|
8376
10985
|
function useSharedTileTextureManager() {
|
|
8377
|
-
return
|
|
10986
|
+
return useContext21(TileTextureManagerContext);
|
|
8378
10987
|
}
|
|
8379
10988
|
|
|
8380
10989
|
// src/tile/tile.tsx
|
|
8381
10990
|
import { useFrame as useFrame11, useThree as useThree18 } from "@react-three/fiber";
|
|
8382
10991
|
import {
|
|
8383
10992
|
memo,
|
|
8384
|
-
useEffect as
|
|
10993
|
+
useEffect as useEffect25,
|
|
8385
10994
|
useMemo as useMemo17,
|
|
8386
|
-
useRef as
|
|
10995
|
+
useRef as useRef24,
|
|
8387
10996
|
useState as useState10
|
|
8388
10997
|
} from "react";
|
|
8389
10998
|
import {
|
|
@@ -8395,7 +11004,7 @@ import {
|
|
|
8395
11004
|
PerspectiveCamera as PerspectiveCamera4,
|
|
8396
11005
|
SRGBColorSpace as SRGBColorSpace4,
|
|
8397
11006
|
TextureLoader as TextureLoader4,
|
|
8398
|
-
Vector3 as
|
|
11007
|
+
Vector3 as Vector312
|
|
8399
11008
|
} from "three";
|
|
8400
11009
|
|
|
8401
11010
|
// src/tile/face-layout.ts
|
|
@@ -8403,7 +11012,7 @@ import {
|
|
|
8403
11012
|
Box3,
|
|
8404
11013
|
Euler as Euler3,
|
|
8405
11014
|
Quaternion as Quaternion2,
|
|
8406
|
-
Vector3 as
|
|
11015
|
+
Vector3 as Vector311
|
|
8407
11016
|
} from "three";
|
|
8408
11017
|
var CUBE_FACES = ["f", "r", "b", "l", "u", "d"];
|
|
8409
11018
|
var PREVIEW_FACE_ORDER = ["l", "f", "r", "b", "u", "d"];
|
|
@@ -8467,12 +11076,12 @@ function getTileBoundingBox(address, radius = CUBE_RADIUS) {
|
|
|
8467
11076
|
const halfWidth = local.width / 2;
|
|
8468
11077
|
const halfHeight = local.height / 2;
|
|
8469
11078
|
const quaternion = getFaceQuaternion(address.face);
|
|
8470
|
-
const position = new
|
|
11079
|
+
const position = new Vector311(...transform.position);
|
|
8471
11080
|
const corners = [
|
|
8472
|
-
new
|
|
8473
|
-
new
|
|
8474
|
-
new
|
|
8475
|
-
new
|
|
11081
|
+
new Vector311(local.x - halfWidth, local.y - halfHeight, 0),
|
|
11082
|
+
new Vector311(local.x + halfWidth, local.y - halfHeight, 0),
|
|
11083
|
+
new Vector311(local.x - halfWidth, local.y + halfHeight, 0),
|
|
11084
|
+
new Vector311(local.x + halfWidth, local.y + halfHeight, 0)
|
|
8476
11085
|
];
|
|
8477
11086
|
for (const corner of corners) {
|
|
8478
11087
|
corner.applyQuaternion(quaternion).add(position);
|
|
@@ -8590,9 +11199,9 @@ var PREVIEW_RADIUS = CUBE_RADIUS + 0.05;
|
|
|
8590
11199
|
var SHARED_TILE_GEOMETRY = new PlaneGeometry4(1, 1);
|
|
8591
11200
|
function usePreviewTexture(url, anisotropy, onError) {
|
|
8592
11201
|
const [texture, setTexture] = useState10(null);
|
|
8593
|
-
const onErrorRef =
|
|
11202
|
+
const onErrorRef = useRef24(onError);
|
|
8594
11203
|
onErrorRef.current = onError;
|
|
8595
|
-
|
|
11204
|
+
useEffect25(() => {
|
|
8596
11205
|
if (!url) {
|
|
8597
11206
|
setTexture(null);
|
|
8598
11207
|
return;
|
|
@@ -8629,7 +11238,7 @@ function usePreviewTexture(url, anisotropy, onError) {
|
|
|
8629
11238
|
active = false;
|
|
8630
11239
|
};
|
|
8631
11240
|
}, [anisotropy, url]);
|
|
8632
|
-
|
|
11241
|
+
useEffect25(
|
|
8633
11242
|
() => () => {
|
|
8634
11243
|
texture?.dispose();
|
|
8635
11244
|
},
|
|
@@ -8660,7 +11269,7 @@ function PreviewFace({
|
|
|
8660
11269
|
uv.needsUpdate = true;
|
|
8661
11270
|
return nextGeometry;
|
|
8662
11271
|
}, [face, faceOrder]);
|
|
8663
|
-
|
|
11272
|
+
useEffect25(
|
|
8664
11273
|
() => () => {
|
|
8665
11274
|
geometry.dispose();
|
|
8666
11275
|
},
|
|
@@ -8708,7 +11317,7 @@ function useManagedTexture(manager, key, url, address) {
|
|
|
8708
11317
|
snapshot: manager.getSnapshot(key)
|
|
8709
11318
|
}));
|
|
8710
11319
|
const snapshot = managedState.manager === manager && managedState.key === key && managedState.url === url ? managedState.snapshot : manager.getSnapshot(key);
|
|
8711
|
-
|
|
11320
|
+
useEffect25(
|
|
8712
11321
|
() => manager.acquire(key, url, address, (nextSnapshot) => {
|
|
8713
11322
|
setManagedState({
|
|
8714
11323
|
manager,
|
|
@@ -8859,8 +11468,8 @@ function parentAddresses(child, parentLevel, parentFaceSize, tileSize) {
|
|
|
8859
11468
|
return addresses;
|
|
8860
11469
|
}
|
|
8861
11470
|
function centerFacingAddress(candidates, camera) {
|
|
8862
|
-
const direction = camera.getWorldDirection(new
|
|
8863
|
-
const center = new
|
|
11471
|
+
const direction = camera.getWorldDirection(new Vector312());
|
|
11472
|
+
const center = new Vector312();
|
|
8864
11473
|
let bestCandidate = candidates[0];
|
|
8865
11474
|
let bestAlignment = -Infinity;
|
|
8866
11475
|
for (const candidate of candidates) {
|
|
@@ -8943,9 +11552,9 @@ function Tile({
|
|
|
8943
11552
|
onPreviewError
|
|
8944
11553
|
);
|
|
8945
11554
|
const sharedManager = useSharedTileTextureManager();
|
|
8946
|
-
const progressRef =
|
|
8947
|
-
const errorRef =
|
|
8948
|
-
const levelChangeRef =
|
|
11555
|
+
const progressRef = useRef24(onLoadProgress);
|
|
11556
|
+
const errorRef = useRef24(onTileError);
|
|
11557
|
+
const levelChangeRef = useRef24(onLevelChange);
|
|
8949
11558
|
progressRef.current = onLoadProgress;
|
|
8950
11559
|
errorRef.current = onTileError;
|
|
8951
11560
|
levelChangeRef.current = onLevelChange;
|
|
@@ -8970,7 +11579,7 @@ function Tile({
|
|
|
8970
11579
|
]
|
|
8971
11580
|
);
|
|
8972
11581
|
const manager = sharedManager ?? ownedManager;
|
|
8973
|
-
|
|
11582
|
+
useEffect25(() => {
|
|
8974
11583
|
manager.resume();
|
|
8975
11584
|
return () => {
|
|
8976
11585
|
if (manager === ownedManager) {
|
|
@@ -8980,11 +11589,11 @@ function Tile({
|
|
|
8980
11589
|
queueMicrotask(() => manager.releaseUnused());
|
|
8981
11590
|
};
|
|
8982
11591
|
}, [manager, ownedManager]);
|
|
8983
|
-
const readyRef =
|
|
8984
|
-
|
|
11592
|
+
const readyRef = useRef24(false);
|
|
11593
|
+
useEffect25(() => {
|
|
8985
11594
|
readyRef.current = false;
|
|
8986
11595
|
}, [effectivePreviewUrl]);
|
|
8987
|
-
|
|
11596
|
+
useEffect25(() => {
|
|
8988
11597
|
if (!previewTexture || readyRef.current) {
|
|
8989
11598
|
return;
|
|
8990
11599
|
}
|
|
@@ -9000,23 +11609,23 @@ function Tile({
|
|
|
9000
11609
|
[baseUrl, resolveTileUrl, template]
|
|
9001
11610
|
);
|
|
9002
11611
|
const [layers, setLayers] = useState10([]);
|
|
9003
|
-
const layerTokenRef =
|
|
9004
|
-
const currentLevelRef =
|
|
9005
|
-
const lastUpdateAtRef =
|
|
9006
|
-
const visibilityDirtyRef =
|
|
9007
|
-
const lastVisibilityQuaternionRef =
|
|
9008
|
-
const lastVisibilityFovRef =
|
|
9009
|
-
const lastViewportRef =
|
|
9010
|
-
const frustumRef =
|
|
9011
|
-
const projectionMatrixRef =
|
|
9012
|
-
const visibilityCameraRef =
|
|
9013
|
-
|
|
11612
|
+
const layerTokenRef = useRef24("");
|
|
11613
|
+
const currentLevelRef = useRef24(1);
|
|
11614
|
+
const lastUpdateAtRef = useRef24(-Infinity);
|
|
11615
|
+
const visibilityDirtyRef = useRef24(true);
|
|
11616
|
+
const lastVisibilityQuaternionRef = useRef24(camera.quaternion.clone());
|
|
11617
|
+
const lastVisibilityFovRef = useRef24(Number.NaN);
|
|
11618
|
+
const lastViewportRef = useRef24({ width: 0, height: 0, dpr: 0 });
|
|
11619
|
+
const frustumRef = useRef24(new Frustum());
|
|
11620
|
+
const projectionMatrixRef = useRef24(new Matrix4());
|
|
11621
|
+
const visibilityCameraRef = useRef24(new PerspectiveCamera4());
|
|
11622
|
+
useEffect25(() => {
|
|
9014
11623
|
currentLevelRef.current = 1;
|
|
9015
11624
|
layerTokenRef.current = "";
|
|
9016
11625
|
visibilityDirtyRef.current = true;
|
|
9017
11626
|
setLayers([]);
|
|
9018
11627
|
}, [manager, multiresToken]);
|
|
9019
|
-
|
|
11628
|
+
useEffect25(() => {
|
|
9020
11629
|
if (loadMode !== "preview") {
|
|
9021
11630
|
return;
|
|
9022
11631
|
}
|
|
@@ -9167,9 +11776,9 @@ function SnapshotCapture({
|
|
|
9167
11776
|
onCaptured
|
|
9168
11777
|
}) {
|
|
9169
11778
|
const { camera, gl, scene, size } = useThree19();
|
|
9170
|
-
const capturedRequestRef =
|
|
9171
|
-
const renderTargetRef =
|
|
9172
|
-
|
|
11779
|
+
const capturedRequestRef = useRef25(0);
|
|
11780
|
+
const renderTargetRef = useRef25(null);
|
|
11781
|
+
useEffect26(
|
|
9173
11782
|
() => () => {
|
|
9174
11783
|
renderTargetRef.current?.dispose();
|
|
9175
11784
|
renderTargetRef.current = null;
|
|
@@ -9224,7 +11833,7 @@ function ScenesController({
|
|
|
9224
11833
|
onTransitionError,
|
|
9225
11834
|
snapshotMaxPixels = 3686400
|
|
9226
11835
|
}) {
|
|
9227
|
-
const controlsRef =
|
|
11836
|
+
const controlsRef = useContext22(PanoramaViewContext);
|
|
9228
11837
|
const manager = useSharedTileTextureManager();
|
|
9229
11838
|
const transition = useMemo18(
|
|
9230
11839
|
() => resolveTransition(transitionInput),
|
|
@@ -9247,13 +11856,13 @@ function ScenesController({
|
|
|
9247
11856
|
const [transitionRunId, setTransitionRunId] = useState11(0);
|
|
9248
11857
|
const [snapshot, setSnapshot] = useState11(null);
|
|
9249
11858
|
const [recoveryKey, setRecoveryKey] = useState11(0);
|
|
9250
|
-
const requestedSceneIdRef =
|
|
9251
|
-
const captureReasonRef =
|
|
9252
|
-
const interactionReleaseRef =
|
|
9253
|
-
const slotsRef =
|
|
9254
|
-
const phaseRef =
|
|
9255
|
-
const liveSlotRef =
|
|
9256
|
-
const transitionFromRef =
|
|
11859
|
+
const requestedSceneIdRef = useRef25(activeSceneId);
|
|
11860
|
+
const captureReasonRef = useRef25("start");
|
|
11861
|
+
const interactionReleaseRef = useRef25(null);
|
|
11862
|
+
const slotsRef = useRef25(slots);
|
|
11863
|
+
const phaseRef = useRef25(phase);
|
|
11864
|
+
const liveSlotRef = useRef25(liveSlot);
|
|
11865
|
+
const transitionFromRef = useRef25(initialScene);
|
|
9257
11866
|
slotsRef.current = slots;
|
|
9258
11867
|
phaseRef.current = phase;
|
|
9259
11868
|
liveSlotRef.current = liveSlot;
|
|
@@ -9275,7 +11884,7 @@ function ScenesController({
|
|
|
9275
11884
|
setPendingSlot(nextSlot);
|
|
9276
11885
|
setPhase("preloading");
|
|
9277
11886
|
}, []);
|
|
9278
|
-
|
|
11887
|
+
useEffect26(() => {
|
|
9279
11888
|
const requested = sceneMap.get(activeSceneId);
|
|
9280
11889
|
if (!requested) {
|
|
9281
11890
|
reportError(activeSceneId, new Error(`Unknown panorama scene: ${activeSceneId}`));
|
|
@@ -9377,12 +11986,12 @@ function ScenesController({
|
|
|
9377
11986
|
});
|
|
9378
11987
|
}
|
|
9379
11988
|
}, [onTransitionEnd, pendingSlot, releaseInteraction, snapshot, transition.preset]);
|
|
9380
|
-
|
|
11989
|
+
useEffect26(() => () => {
|
|
9381
11990
|
releaseInteraction();
|
|
9382
11991
|
snapshot?.dispose();
|
|
9383
11992
|
}, [releaseInteraction, snapshot]);
|
|
9384
11993
|
const { gl } = useThree19();
|
|
9385
|
-
|
|
11994
|
+
useEffect26(() => {
|
|
9386
11995
|
const canvas = gl.domElement;
|
|
9387
11996
|
const onContextLost = (event) => {
|
|
9388
11997
|
event.preventDefault();
|
|
@@ -9465,7 +12074,7 @@ function Scenes({
|
|
|
9465
12074
|
|
|
9466
12075
|
// src/hotspot/image-hotspot.tsx
|
|
9467
12076
|
import { useThree as useThree21 } from "@react-three/fiber";
|
|
9468
|
-
import { useEffect as
|
|
12077
|
+
import { useEffect as useEffect29, useRef as useRef27, useState as useState14 } from "react";
|
|
9469
12078
|
import {
|
|
9470
12079
|
ClampToEdgeWrapping as ClampToEdgeWrapping3,
|
|
9471
12080
|
LinearFilter as LinearFilter6,
|
|
@@ -9477,35 +12086,35 @@ import {
|
|
|
9477
12086
|
// src/hotspot/hotspot-anchor.tsx
|
|
9478
12087
|
import { useFrame as useFrame13, useThree as useThree20 } from "@react-three/fiber";
|
|
9479
12088
|
import {
|
|
9480
|
-
useContext as
|
|
9481
|
-
useEffect as
|
|
12089
|
+
useContext as useContext24,
|
|
12090
|
+
useEffect as useEffect28,
|
|
9482
12091
|
useLayoutEffect as useLayoutEffect4,
|
|
9483
12092
|
useMemo as useMemo20,
|
|
9484
|
-
useRef as
|
|
12093
|
+
useRef as useRef26,
|
|
9485
12094
|
useState as useState13
|
|
9486
12095
|
} from "react";
|
|
9487
12096
|
import {
|
|
9488
12097
|
Box3 as Box33,
|
|
9489
12098
|
EdgesGeometry,
|
|
9490
|
-
MathUtils as
|
|
12099
|
+
MathUtils as MathUtils7,
|
|
9491
12100
|
Matrix4 as Matrix42,
|
|
9492
12101
|
Plane,
|
|
9493
12102
|
PlaneGeometry as PlaneGeometry5,
|
|
9494
12103
|
PerspectiveCamera as PerspectiveCamera5,
|
|
9495
12104
|
Quaternion as Quaternion3,
|
|
9496
12105
|
Ray,
|
|
9497
|
-
Vector3 as
|
|
12106
|
+
Vector3 as Vector313
|
|
9498
12107
|
} from "three";
|
|
9499
12108
|
|
|
9500
12109
|
// src/hotspot/hotspot-tooltip.tsx
|
|
9501
|
-
import { useEffect as
|
|
12110
|
+
import { useEffect as useEffect27, useMemo as useMemo19, useState as useState12 } from "react";
|
|
9502
12111
|
|
|
9503
12112
|
// src/webvr/stereo-html.tsx
|
|
9504
12113
|
import { Html } from "@react-three/drei";
|
|
9505
|
-
import { useContext as
|
|
12114
|
+
import { useContext as useContext23, useSyncExternalStore as useSyncExternalStore6 } from "react";
|
|
9506
12115
|
import { Fragment as Fragment7, jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
9507
12116
|
function useFallbackStereoView() {
|
|
9508
|
-
const runtime =
|
|
12117
|
+
const runtime = useContext23(WebVRRuntimeContext);
|
|
9509
12118
|
const host = runtime?.host ?? null;
|
|
9510
12119
|
const fallback = useSyncExternalStore6(
|
|
9511
12120
|
(onStoreChange) => host ? subscribeWebVRHost(host, onStoreChange) : () => void 0,
|
|
@@ -9622,7 +12231,7 @@ function HotspotTooltip({
|
|
|
9622
12231
|
appearance
|
|
9623
12232
|
}) {
|
|
9624
12233
|
const [imageFailed, setImageFailed] = useState12(false);
|
|
9625
|
-
|
|
12234
|
+
useEffect27(() => {
|
|
9626
12235
|
setImageFailed(false);
|
|
9627
12236
|
}, [content.image]);
|
|
9628
12237
|
const showImage = Boolean(content.image) && !imageFailed;
|
|
@@ -9680,28 +12289,28 @@ var DEFAULT_REFERENCE_FOV = 75;
|
|
|
9680
12289
|
var MIN_ANGULAR_SIZE = 0.01;
|
|
9681
12290
|
var MAX_ANGULAR_SIZE = 179;
|
|
9682
12291
|
var DRAG_EPSILON_DEGREES = 1e-3;
|
|
9683
|
-
var LOCAL_FORWARD = new
|
|
12292
|
+
var LOCAL_FORWARD = new Vector313(0, 0, 1);
|
|
9684
12293
|
var TOOLTIP_WORLD_BOX = new Box33();
|
|
9685
12294
|
var TOOLTIP_LOCAL_BOX = new Box33();
|
|
9686
|
-
var TOOLTIP_CORNER = new
|
|
12295
|
+
var TOOLTIP_CORNER = new Vector313();
|
|
9687
12296
|
var TOOLTIP_INVERSE = new Matrix42();
|
|
9688
|
-
var TOOLTIP_WORLD_CORNER = new
|
|
9689
|
-
var TOOLTIP_PROJECTED = new
|
|
9690
|
-
var TOOLTIP_RAY_ORIGIN = new
|
|
9691
|
-
var TOOLTIP_RAY_FAR = new
|
|
9692
|
-
var TOOLTIP_RAY_DIRECTION = new
|
|
12297
|
+
var TOOLTIP_WORLD_CORNER = new Vector313();
|
|
12298
|
+
var TOOLTIP_PROJECTED = new Vector313();
|
|
12299
|
+
var TOOLTIP_RAY_ORIGIN = new Vector313();
|
|
12300
|
+
var TOOLTIP_RAY_FAR = new Vector313();
|
|
12301
|
+
var TOOLTIP_RAY_DIRECTION = new Vector313();
|
|
9693
12302
|
var TOOLTIP_RAY = new Ray();
|
|
9694
12303
|
var TOOLTIP_PLANE = new Plane();
|
|
9695
|
-
var TOOLTIP_INTERSECTION = new
|
|
9696
|
-
var TOOLTIP_PLANE_NORMAL = new
|
|
9697
|
-
var TOOLTIP_PLANE_POINT = new
|
|
12304
|
+
var TOOLTIP_INTERSECTION = new Vector313();
|
|
12305
|
+
var TOOLTIP_PLANE_NORMAL = new Vector313();
|
|
12306
|
+
var TOOLTIP_PLANE_POINT = new Vector313();
|
|
9698
12307
|
var HOTSPOT_MODE_RENDERING = {
|
|
9699
12308
|
surface: { orientation: "surface", placement: "surface" },
|
|
9700
12309
|
billboard: { orientation: "billboard", placement: "floating" }
|
|
9701
12310
|
};
|
|
9702
12311
|
function angularSizeToWorldSize(size, radius) {
|
|
9703
|
-
const safeSize = Number.isFinite(size) ?
|
|
9704
|
-
return 2 * radius * Math.tan(
|
|
12312
|
+
const safeSize = Number.isFinite(size) ? MathUtils7.clamp(Math.abs(size), MIN_ANGULAR_SIZE, MAX_ANGULAR_SIZE) : MIN_ANGULAR_SIZE;
|
|
12313
|
+
return 2 * radius * Math.tan(MathUtils7.degToRad(safeSize) / 2);
|
|
9705
12314
|
}
|
|
9706
12315
|
function resolveScale(scale) {
|
|
9707
12316
|
return Number.isFinite(scale) && scale > 0 ? scale : 1;
|
|
@@ -9714,7 +12323,7 @@ function resolveDistance(placement, distance, width, height) {
|
|
|
9714
12323
|
if (!Number.isFinite(distance)) {
|
|
9715
12324
|
return DEFAULT_FLOATING_DISTANCE;
|
|
9716
12325
|
}
|
|
9717
|
-
return
|
|
12326
|
+
return MathUtils7.clamp(Math.abs(distance), 0.1, maximumDistance);
|
|
9718
12327
|
}
|
|
9719
12328
|
function applyHotspotTransform(group, camera, orientation2, surfaceQuaternion3, rotation, scaleMode, referenceFov, useAngularScale, worldWidth, worldHeight) {
|
|
9720
12329
|
if (orientation2 === "billboard") {
|
|
@@ -9722,7 +12331,7 @@ function applyHotspotTransform(group, camera, orientation2, surfaceQuaternion3,
|
|
|
9722
12331
|
} else {
|
|
9723
12332
|
group.quaternion.copy(surfaceQuaternion3);
|
|
9724
12333
|
}
|
|
9725
|
-
group.rotateOnAxis(LOCAL_FORWARD,
|
|
12334
|
+
group.rotateOnAxis(LOCAL_FORWARD, MathUtils7.degToRad(-rotation));
|
|
9726
12335
|
const scaleFactor = scaleMode === "fixed" && camera instanceof PerspectiveCamera5 ? fixedScaleFactor(camera.fov, referenceFov) : 1;
|
|
9727
12336
|
group.scale.set(
|
|
9728
12337
|
(useAngularScale ? worldWidth : 1) * scaleFactor,
|
|
@@ -9732,33 +12341,33 @@ function applyHotspotTransform(group, camera, orientation2, surfaceQuaternion3,
|
|
|
9732
12341
|
group.updateMatrixWorld();
|
|
9733
12342
|
}
|
|
9734
12343
|
function maximumHotspotDistance(width, height) {
|
|
9735
|
-
const safeWidth =
|
|
12344
|
+
const safeWidth = MathUtils7.clamp(
|
|
9736
12345
|
Math.abs(Number.isFinite(width) ? width : MIN_ANGULAR_SIZE),
|
|
9737
12346
|
MIN_ANGULAR_SIZE,
|
|
9738
12347
|
MAX_ANGULAR_SIZE
|
|
9739
12348
|
);
|
|
9740
|
-
const safeHeight =
|
|
12349
|
+
const safeHeight = MathUtils7.clamp(
|
|
9741
12350
|
Math.abs(Number.isFinite(height) ? height : MIN_ANGULAR_SIZE),
|
|
9742
12351
|
MIN_ANGULAR_SIZE,
|
|
9743
12352
|
MAX_ANGULAR_SIZE
|
|
9744
12353
|
);
|
|
9745
12354
|
const cornerFactor = Math.hypot(
|
|
9746
12355
|
1,
|
|
9747
|
-
Math.tan(
|
|
9748
|
-
Math.tan(
|
|
12356
|
+
Math.tan(MathUtils7.degToRad(safeWidth) / 2),
|
|
12357
|
+
Math.tan(MathUtils7.degToRad(safeHeight) / 2)
|
|
9749
12358
|
);
|
|
9750
12359
|
return (PANORAMA_RADIUS - PANORAMA_SURFACE_INSET) / cornerFactor;
|
|
9751
12360
|
}
|
|
9752
12361
|
function fixedScaleFactor(cameraFov, referenceFov) {
|
|
9753
|
-
const safeReferenceFov =
|
|
9754
|
-
return Math.tan(
|
|
12362
|
+
const safeReferenceFov = MathUtils7.clamp(referenceFov, 1, 179);
|
|
12363
|
+
return Math.tan(MathUtils7.degToRad(cameraFov) / 2) / Math.tan(MathUtils7.degToRad(safeReferenceFov) / 2);
|
|
9755
12364
|
}
|
|
9756
12365
|
function createSurfaceQuaternion(position) {
|
|
9757
12366
|
const outward = panoPositionToVector3(position).normalize();
|
|
9758
12367
|
const inward = outward.clone().negate();
|
|
9759
|
-
const pitch =
|
|
9760
|
-
const yaw =
|
|
9761
|
-
const localUp = new
|
|
12368
|
+
const pitch = MathUtils7.degToRad(position.pitch);
|
|
12369
|
+
const yaw = MathUtils7.degToRad(position.yaw);
|
|
12370
|
+
const localUp = new Vector313(
|
|
9762
12371
|
-Math.sin(pitch) * Math.sin(yaw),
|
|
9763
12372
|
Math.cos(pitch),
|
|
9764
12373
|
Math.sin(pitch) * Math.cos(yaw)
|
|
@@ -9778,7 +12387,7 @@ function makeInteractionEvent(id, position, event) {
|
|
|
9778
12387
|
function angularDistance(a, b) {
|
|
9779
12388
|
const aVector = panoPositionToVector3(a);
|
|
9780
12389
|
const bVector = panoPositionToVector3(b);
|
|
9781
|
-
return
|
|
12390
|
+
return MathUtils7.radToDeg(aVector.angleTo(bVector));
|
|
9782
12391
|
}
|
|
9783
12392
|
function isTooltipOpen(trigger, hovered, focused, pinned) {
|
|
9784
12393
|
switch (trigger) {
|
|
@@ -10009,14 +12618,14 @@ function HotspotAnchor({
|
|
|
10009
12618
|
onPositionChange,
|
|
10010
12619
|
onDragEnd
|
|
10011
12620
|
}) {
|
|
10012
|
-
const controlsRef =
|
|
10013
|
-
const eventBus =
|
|
12621
|
+
const controlsRef = useContext24(PanoramaViewContext);
|
|
12622
|
+
const eventBus = useContext24(PanoEventBusContext);
|
|
10014
12623
|
const cursorApi = usePanoCursor();
|
|
10015
12624
|
const { camera, size } = useThree20();
|
|
10016
|
-
const groupRef =
|
|
10017
|
-
const tooltipAnchorRef =
|
|
10018
|
-
const dragStateRef =
|
|
10019
|
-
const suppressNextClickRef =
|
|
12625
|
+
const groupRef = useRef26(null);
|
|
12626
|
+
const tooltipAnchorRef = useRef26(null);
|
|
12627
|
+
const dragStateRef = useRef26(null);
|
|
12628
|
+
const suppressNextClickRef = useRef26(false);
|
|
10020
12629
|
const [hovered, setHovered] = useState13(false);
|
|
10021
12630
|
const [dragging, setDragging] = useState13(false);
|
|
10022
12631
|
const [pinned, setPinned] = useState13(false);
|
|
@@ -10073,14 +12682,14 @@ function HotspotAnchor({
|
|
|
10073
12682
|
});
|
|
10074
12683
|
const tooltipOpen = visible && tooltipContent !== null && isTooltipOpen(tooltipTrigger, hovered, focused, pinned);
|
|
10075
12684
|
const cursorClaimId = hotspotCursorClaimId(id);
|
|
10076
|
-
|
|
12685
|
+
useEffect28(
|
|
10077
12686
|
() => () => {
|
|
10078
12687
|
dragStateRef.current?.releaseInteractionLock();
|
|
10079
12688
|
dragStateRef.current = null;
|
|
10080
12689
|
},
|
|
10081
12690
|
[]
|
|
10082
12691
|
);
|
|
10083
|
-
|
|
12692
|
+
useEffect28(() => {
|
|
10084
12693
|
if (!cursorApi) {
|
|
10085
12694
|
return;
|
|
10086
12695
|
}
|
|
@@ -10102,14 +12711,14 @@ function HotspotAnchor({
|
|
|
10102
12711
|
hovered,
|
|
10103
12712
|
visible
|
|
10104
12713
|
]);
|
|
10105
|
-
|
|
12714
|
+
useEffect28(
|
|
10106
12715
|
() => () => {
|
|
10107
12716
|
cursorApi?.release(cursorClaimId);
|
|
10108
12717
|
},
|
|
10109
12718
|
[cursorApi, cursorClaimId]
|
|
10110
12719
|
);
|
|
10111
|
-
|
|
10112
|
-
|
|
12720
|
+
useEffect28(() => () => focusGeometry.dispose(), [focusGeometry]);
|
|
12721
|
+
useEffect28(() => {
|
|
10113
12722
|
if (tooltipTrigger !== "click") {
|
|
10114
12723
|
setPinned(false);
|
|
10115
12724
|
return;
|
|
@@ -10118,12 +12727,12 @@ function HotspotAnchor({
|
|
|
10118
12727
|
setPinned(false);
|
|
10119
12728
|
});
|
|
10120
12729
|
}, [eventBus, tooltipTrigger]);
|
|
10121
|
-
|
|
12730
|
+
useEffect28(() => {
|
|
10122
12731
|
if (tooltipTrigger !== "hover") {
|
|
10123
12732
|
setHovered(false);
|
|
10124
12733
|
}
|
|
10125
12734
|
}, [tooltipTrigger]);
|
|
10126
|
-
|
|
12735
|
+
useEffect28(() => {
|
|
10127
12736
|
if (acceptsPointer) {
|
|
10128
12737
|
return;
|
|
10129
12738
|
}
|
|
@@ -10468,11 +13077,11 @@ import { jsx as jsx27 } from "react/jsx-runtime";
|
|
|
10468
13077
|
function useHotspotImageTexture(src, onLoad, onError) {
|
|
10469
13078
|
const gl = useThree21((state) => state.gl);
|
|
10470
13079
|
const [texture, setTexture] = useState14(null);
|
|
10471
|
-
const onLoadRef =
|
|
10472
|
-
const onErrorRef =
|
|
13080
|
+
const onLoadRef = useRef27(onLoad);
|
|
13081
|
+
const onErrorRef = useRef27(onError);
|
|
10473
13082
|
onLoadRef.current = onLoad;
|
|
10474
13083
|
onErrorRef.current = onError;
|
|
10475
|
-
|
|
13084
|
+
useEffect29(() => {
|
|
10476
13085
|
let active = true;
|
|
10477
13086
|
setTexture(null);
|
|
10478
13087
|
if (!src) {
|
|
@@ -10510,7 +13119,7 @@ function useHotspotImageTexture(src, onLoad, onError) {
|
|
|
10510
13119
|
active = false;
|
|
10511
13120
|
};
|
|
10512
13121
|
}, [gl, src]);
|
|
10513
|
-
|
|
13122
|
+
useEffect29(
|
|
10514
13123
|
() => () => {
|
|
10515
13124
|
texture?.dispose();
|
|
10516
13125
|
},
|
|
@@ -10532,7 +13141,7 @@ function ImageHotspot({
|
|
|
10532
13141
|
}
|
|
10533
13142
|
|
|
10534
13143
|
// src/hotspot/polygon-hotspot.tsx
|
|
10535
|
-
import { useEffect as
|
|
13144
|
+
import { useEffect as useEffect30, useMemo as useMemo21, useRef as useRef29 } from "react";
|
|
10536
13145
|
import {
|
|
10537
13146
|
BufferGeometry,
|
|
10538
13147
|
DoubleSide as DoubleSide5,
|
|
@@ -10541,20 +13150,20 @@ import {
|
|
|
10541
13150
|
Quaternion as Quaternion4,
|
|
10542
13151
|
ShapeUtils,
|
|
10543
13152
|
Vector2 as Vector27,
|
|
10544
|
-
Vector3 as
|
|
13153
|
+
Vector3 as Vector315
|
|
10545
13154
|
} from "three";
|
|
10546
13155
|
|
|
10547
13156
|
// src/hotspot/hotspot-stroke-line.tsx
|
|
10548
13157
|
import { Line } from "@react-three/drei";
|
|
10549
13158
|
import { useFrame as useFrame14, useThree as useThree22 } from "@react-three/fiber";
|
|
10550
|
-
import { useLayoutEffect as useLayoutEffect5, useRef as
|
|
13159
|
+
import { useLayoutEffect as useLayoutEffect5, useRef as useRef28 } from "react";
|
|
10551
13160
|
import {
|
|
10552
|
-
MathUtils as
|
|
13161
|
+
MathUtils as MathUtils8,
|
|
10553
13162
|
PerspectiveCamera as PerspectiveCamera6,
|
|
10554
|
-
Vector3 as
|
|
13163
|
+
Vector3 as Vector314
|
|
10555
13164
|
} from "three";
|
|
10556
13165
|
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
10557
|
-
var LINE_WORLD_POSITION = new
|
|
13166
|
+
var LINE_WORLD_POSITION = new Vector314();
|
|
10558
13167
|
function applyScreenSpaceDashScale(object, camera, viewportHeight) {
|
|
10559
13168
|
const material = object?.material;
|
|
10560
13169
|
if (!object || typeof material?.dashScale !== "number") {
|
|
@@ -10563,7 +13172,7 @@ function applyScreenSpaceDashScale(object, camera, viewportHeight) {
|
|
|
10563
13172
|
object.getWorldPosition(LINE_WORLD_POSITION);
|
|
10564
13173
|
const depth = Math.max(camera.position.distanceTo(LINE_WORLD_POSITION), 1);
|
|
10565
13174
|
const fov = camera instanceof PerspectiveCamera6 ? camera.fov : 75;
|
|
10566
|
-
material.dashScale = viewportHeight / (2 * Math.tan(
|
|
13175
|
+
material.dashScale = viewportHeight / (2 * Math.tan(MathUtils8.degToRad(fov) * 0.5) * depth);
|
|
10567
13176
|
}
|
|
10568
13177
|
function resolveDash(dashSize, gapSize) {
|
|
10569
13178
|
if (dashSize === void 0 || !Number.isFinite(dashSize) || dashSize <= 0) {
|
|
@@ -10584,7 +13193,7 @@ function HotspotStrokeLine({
|
|
|
10584
13193
|
dashSize,
|
|
10585
13194
|
gapSize
|
|
10586
13195
|
}) {
|
|
10587
|
-
const lineRef =
|
|
13196
|
+
const lineRef = useRef28(null);
|
|
10588
13197
|
const { camera, size } = useThree22();
|
|
10589
13198
|
const dash = resolveDash(dashSize, gapSize);
|
|
10590
13199
|
useLayoutEffect5(() => {
|
|
@@ -10693,7 +13302,7 @@ function polygonContainsDirection(vertices, direction) {
|
|
|
10693
13302
|
}
|
|
10694
13303
|
function fitsHemisphere(vertices) {
|
|
10695
13304
|
const directions = vertices.map((vertex) => panoPositionToVector3(vertex).normalize());
|
|
10696
|
-
const candidates = [new
|
|
13305
|
+
const candidates = [new Vector315()];
|
|
10697
13306
|
for (const direction of directions) {
|
|
10698
13307
|
candidates[0].add(direction);
|
|
10699
13308
|
candidates.push(direction.clone());
|
|
@@ -10717,7 +13326,7 @@ function validatePolygonVertices(vertices) {
|
|
|
10717
13326
|
if (hasSelfIntersection(unwrapped)) {
|
|
10718
13327
|
issues.push({ code: "self_intersection", message: "Polygon edges cannot cross." });
|
|
10719
13328
|
}
|
|
10720
|
-
if (polygonContainsDirection(normalized, new
|
|
13329
|
+
if (polygonContainsDirection(normalized, new Vector315(0, 1, 0)) || polygonContainsDirection(normalized, new Vector315(0, -1, 0))) {
|
|
10721
13330
|
issues.push({ code: "contains_pole", message: "Polygons cannot contain a panorama pole." });
|
|
10722
13331
|
}
|
|
10723
13332
|
if (!fitsHemisphere(normalized)) {
|
|
@@ -10728,7 +13337,7 @@ function validatePolygonVertices(vertices) {
|
|
|
10728
13337
|
function polygonCenter(vertices) {
|
|
10729
13338
|
const sum = vertices.reduce(
|
|
10730
13339
|
(total, vertex) => total.add(panoPositionToVector3(vertex).normalize()),
|
|
10731
|
-
new
|
|
13340
|
+
new Vector315()
|
|
10732
13341
|
);
|
|
10733
13342
|
return sum.lengthSq() > 1e-8 ? vector3ToPanoPosition(sum) : normalizePanoPosition(vertices[0]);
|
|
10734
13343
|
}
|
|
@@ -10737,7 +13346,7 @@ function surfaceQuaternion(position) {
|
|
|
10737
13346
|
const inward = outward.clone().negate();
|
|
10738
13347
|
const pitch = position.pitch * Math.PI / 180;
|
|
10739
13348
|
const yaw = position.yaw * Math.PI / 180;
|
|
10740
|
-
const localUp = new
|
|
13349
|
+
const localUp = new Vector315(
|
|
10741
13350
|
-Math.sin(pitch) * Math.sin(yaw),
|
|
10742
13351
|
Math.cos(pitch),
|
|
10743
13352
|
Math.sin(pitch) * Math.cos(yaw)
|
|
@@ -10750,7 +13359,7 @@ function makeWorldToLocal(center) {
|
|
|
10750
13359
|
return new Matrix43().compose(
|
|
10751
13360
|
panoPositionToVector3(center, POLYGON_RADIUS),
|
|
10752
13361
|
surfaceQuaternion(center),
|
|
10753
|
-
new
|
|
13362
|
+
new Vector315(1, 1, 1)
|
|
10754
13363
|
).invert();
|
|
10755
13364
|
}
|
|
10756
13365
|
function projectedPoint(a, b, c, weightB, weightC, radius, worldToLocal) {
|
|
@@ -10889,12 +13498,12 @@ function PolygonHotspot({
|
|
|
10889
13498
|
[center, valid, vertices]
|
|
10890
13499
|
);
|
|
10891
13500
|
const resolvedStrokeOpacity = Math.max(0, Math.min(strokeOpacity, 1));
|
|
10892
|
-
const startVerticesRef =
|
|
13501
|
+
const startVerticesRef = useRef29(null);
|
|
10893
13502
|
const issuesKey = issues.map((issue) => issue.code).join(",");
|
|
10894
|
-
|
|
13503
|
+
useEffect30(() => {
|
|
10895
13504
|
if (!valid) onInvalid?.(issues);
|
|
10896
13505
|
}, [issues, issuesKey, onInvalid, valid]);
|
|
10897
|
-
|
|
13506
|
+
useEffect30(() => () => fillGeometry?.dispose(), [fillGeometry]);
|
|
10898
13507
|
if (!valid || !center || !fillGeometry || !strokePoints || strokePoints.length < 2) {
|
|
10899
13508
|
return null;
|
|
10900
13509
|
}
|
|
@@ -10974,12 +13583,12 @@ function PolygonHotspot({
|
|
|
10974
13583
|
}
|
|
10975
13584
|
|
|
10976
13585
|
// src/hotspot/polyline-hotspot.tsx
|
|
10977
|
-
import { useEffect as
|
|
13586
|
+
import { useEffect as useEffect31, useMemo as useMemo22, useRef as useRef30 } from "react";
|
|
10978
13587
|
import {
|
|
10979
|
-
MathUtils as
|
|
13588
|
+
MathUtils as MathUtils9,
|
|
10980
13589
|
Matrix4 as Matrix44,
|
|
10981
13590
|
Quaternion as Quaternion5,
|
|
10982
|
-
Vector3 as
|
|
13591
|
+
Vector3 as Vector316
|
|
10983
13592
|
} from "three";
|
|
10984
13593
|
import { jsx as jsx30 } from "react/jsx-runtime";
|
|
10985
13594
|
var POLYLINE_RADIUS = 990;
|
|
@@ -11006,16 +13615,16 @@ function unwrapVertices(vertices) {
|
|
|
11006
13615
|
function polylineCenter(vertices) {
|
|
11007
13616
|
const sum = vertices.reduce(
|
|
11008
13617
|
(total, vertex) => total.add(panoPositionToVector3(vertex).normalize()),
|
|
11009
|
-
new
|
|
13618
|
+
new Vector316()
|
|
11010
13619
|
);
|
|
11011
13620
|
return sum.lengthSq() > 1e-8 ? vector3ToPanoPosition(sum) : normalizePanoPosition(vertices[0]);
|
|
11012
13621
|
}
|
|
11013
13622
|
function surfaceQuaternion2(position) {
|
|
11014
13623
|
const outward = panoPositionToVector3(position).normalize();
|
|
11015
13624
|
const inward = outward.clone().negate();
|
|
11016
|
-
const pitch =
|
|
11017
|
-
const yaw =
|
|
11018
|
-
const localUp = new
|
|
13625
|
+
const pitch = MathUtils9.degToRad(position.pitch);
|
|
13626
|
+
const yaw = MathUtils9.degToRad(position.yaw);
|
|
13627
|
+
const localUp = new Vector316(
|
|
11019
13628
|
-Math.sin(pitch) * Math.sin(yaw),
|
|
11020
13629
|
Math.cos(pitch),
|
|
11021
13630
|
Math.sin(pitch) * Math.cos(yaw)
|
|
@@ -11028,7 +13637,7 @@ function makeWorldToLocal2(center) {
|
|
|
11028
13637
|
return new Matrix44().compose(
|
|
11029
13638
|
panoPositionToVector3(center, POLYLINE_RADIUS),
|
|
11030
13639
|
surfaceQuaternion2(center),
|
|
11031
|
-
new
|
|
13640
|
+
new Vector316(1, 1, 1)
|
|
11032
13641
|
).invert();
|
|
11033
13642
|
}
|
|
11034
13643
|
function subdivisionSteps(vertices) {
|
|
@@ -11043,7 +13652,7 @@ function subdivisionSteps(vertices) {
|
|
|
11043
13652
|
}
|
|
11044
13653
|
return Math.min(
|
|
11045
13654
|
8,
|
|
11046
|
-
Math.max(1, Math.ceil(
|
|
13655
|
+
Math.max(1, Math.ceil(MathUtils9.radToDeg(maxAngle) / MAX_SEGMENT_DEGREES))
|
|
11047
13656
|
);
|
|
11048
13657
|
}
|
|
11049
13658
|
function makeLinePositions(vertices, center) {
|
|
@@ -11106,8 +13715,8 @@ function PolylineHotspot({
|
|
|
11106
13715
|
[center, valid, vertices]
|
|
11107
13716
|
);
|
|
11108
13717
|
const opacity = Math.max(0, Math.min(strokeOpacity, 1));
|
|
11109
|
-
const startVerticesRef =
|
|
11110
|
-
|
|
13718
|
+
const startVerticesRef = useRef30(null);
|
|
13719
|
+
useEffect31(() => {
|
|
11111
13720
|
if (!valid) onInvalid?.(issues);
|
|
11112
13721
|
}, [issues, onInvalid, valid]);
|
|
11113
13722
|
if (!valid || !center || !linePoints || linePoints.length < 2) return null;
|
|
@@ -11173,7 +13782,7 @@ function PolylineHotspot({
|
|
|
11173
13782
|
}
|
|
11174
13783
|
|
|
11175
13784
|
// src/hotspot/graphic-hotspot.tsx
|
|
11176
|
-
import { useEffect as
|
|
13785
|
+
import { useEffect as useEffect32, useRef as useRef31, useState as useState15 } from "react";
|
|
11177
13786
|
import {
|
|
11178
13787
|
CanvasTexture,
|
|
11179
13788
|
ClampToEdgeWrapping as ClampToEdgeWrapping4,
|
|
@@ -11371,11 +13980,11 @@ function createGraphicTexture(graphic, aspectWidth, aspectHeight) {
|
|
|
11371
13980
|
}
|
|
11372
13981
|
function useGraphicTexture(graphic, aspectWidth, aspectHeight, onLoad, onError) {
|
|
11373
13982
|
const [texture, setTexture] = useState15(null);
|
|
11374
|
-
const onLoadRef =
|
|
11375
|
-
const onErrorRef =
|
|
13983
|
+
const onLoadRef = useRef31(onLoad);
|
|
13984
|
+
const onErrorRef = useRef31(onError);
|
|
11376
13985
|
onLoadRef.current = onLoad;
|
|
11377
13986
|
onErrorRef.current = onError;
|
|
11378
|
-
|
|
13987
|
+
useEffect32(() => {
|
|
11379
13988
|
let nextTexture = null;
|
|
11380
13989
|
try {
|
|
11381
13990
|
nextTexture = createGraphicTexture(graphic, aspectWidth, aspectHeight);
|
|
@@ -11414,7 +14023,7 @@ function GraphicHotspot(props) {
|
|
|
11414
14023
|
|
|
11415
14024
|
// src/hotspot/sequence-hotspot.tsx
|
|
11416
14025
|
import { useFrame as useFrame15, useThree as useThree23 } from "@react-three/fiber";
|
|
11417
|
-
import { useEffect as
|
|
14026
|
+
import { useEffect as useEffect33, useRef as useRef32, useState as useState16 } from "react";
|
|
11418
14027
|
import {
|
|
11419
14028
|
ClampToEdgeWrapping as ClampToEdgeWrapping5,
|
|
11420
14029
|
LinearFilter as LinearFilter8,
|
|
@@ -11438,11 +14047,11 @@ function useSpriteTexture({
|
|
|
11438
14047
|
}) {
|
|
11439
14048
|
const gl = useThree23((state) => state.gl);
|
|
11440
14049
|
const [texture, setTexture] = useState16(null);
|
|
11441
|
-
const onErrorRef =
|
|
11442
|
-
const onLoadProgressRef =
|
|
14050
|
+
const onErrorRef = useRef32(onError);
|
|
14051
|
+
const onLoadProgressRef = useRef32(onLoadProgress);
|
|
11443
14052
|
onErrorRef.current = onError;
|
|
11444
14053
|
onLoadProgressRef.current = onLoadProgress;
|
|
11445
|
-
|
|
14054
|
+
useEffect33(() => {
|
|
11446
14055
|
let active = true;
|
|
11447
14056
|
setTexture(null);
|
|
11448
14057
|
if (!src) {
|
|
@@ -11483,7 +14092,7 @@ function useSpriteTexture({
|
|
|
11483
14092
|
active = false;
|
|
11484
14093
|
};
|
|
11485
14094
|
}, [gl, id, src]);
|
|
11486
|
-
|
|
14095
|
+
useEffect33(
|
|
11487
14096
|
() => () => {
|
|
11488
14097
|
texture?.dispose();
|
|
11489
14098
|
},
|
|
@@ -11513,23 +14122,23 @@ function SequenceHotspot({
|
|
|
11513
14122
|
const frameCount = resolveFrameCount(requestedFrameCount);
|
|
11514
14123
|
const safeFps = resolveFps(fps);
|
|
11515
14124
|
const [frameIndex, setFrameIndex] = useState16(0);
|
|
11516
|
-
const elapsedRef =
|
|
11517
|
-
const frameIndexRef =
|
|
11518
|
-
const endedRef =
|
|
11519
|
-
const lastPlaybackStateRef =
|
|
11520
|
-
const onFrameChangeRef =
|
|
11521
|
-
const onPlaybackStateChangeRef =
|
|
11522
|
-
const onEndedRef =
|
|
14125
|
+
const elapsedRef = useRef32(0);
|
|
14126
|
+
const frameIndexRef = useRef32(0);
|
|
14127
|
+
const endedRef = useRef32(false);
|
|
14128
|
+
const lastPlaybackStateRef = useRef32(null);
|
|
14129
|
+
const onFrameChangeRef = useRef32(onFrameChange);
|
|
14130
|
+
const onPlaybackStateChangeRef = useRef32(onPlaybackStateChange);
|
|
14131
|
+
const onEndedRef = useRef32(onEnded);
|
|
11523
14132
|
onFrameChangeRef.current = onFrameChange;
|
|
11524
14133
|
onPlaybackStateChangeRef.current = onPlaybackStateChange;
|
|
11525
14134
|
onEndedRef.current = onEnded;
|
|
11526
|
-
|
|
14135
|
+
useEffect33(() => {
|
|
11527
14136
|
elapsedRef.current = 0;
|
|
11528
14137
|
frameIndexRef.current = 0;
|
|
11529
14138
|
endedRef.current = false;
|
|
11530
14139
|
setFrameIndex(0);
|
|
11531
14140
|
}, [frameCount, frameDirection, src]);
|
|
11532
|
-
|
|
14141
|
+
useEffect33(() => {
|
|
11533
14142
|
if (!texture) {
|
|
11534
14143
|
return;
|
|
11535
14144
|
}
|
|
@@ -11543,13 +14152,13 @@ function SequenceHotspot({
|
|
|
11543
14152
|
);
|
|
11544
14153
|
texture.needsUpdate = true;
|
|
11545
14154
|
}, [frameCount, frameDirection, frameIndex, texture]);
|
|
11546
|
-
|
|
14155
|
+
useEffect33(() => {
|
|
11547
14156
|
if (!texture) {
|
|
11548
14157
|
return;
|
|
11549
14158
|
}
|
|
11550
14159
|
onFrameChangeRef.current?.({ id, index: 0, src });
|
|
11551
14160
|
}, [id, src, texture]);
|
|
11552
|
-
|
|
14161
|
+
useEffect33(() => {
|
|
11553
14162
|
if (!texture) {
|
|
11554
14163
|
return;
|
|
11555
14164
|
}
|
|
@@ -11603,7 +14212,7 @@ function SequenceHotspot({
|
|
|
11603
14212
|
|
|
11604
14213
|
// src/hotspot/video-hotspot.tsx
|
|
11605
14214
|
import { useThree as useThree24 } from "@react-three/fiber";
|
|
11606
|
-
import { useEffect as
|
|
14215
|
+
import { useEffect as useEffect34, useRef as useRef33, useState as useState17 } from "react";
|
|
11607
14216
|
import {
|
|
11608
14217
|
ClampToEdgeWrapping as ClampToEdgeWrapping6,
|
|
11609
14218
|
LinearFilter as LinearFilter9,
|
|
@@ -11622,9 +14231,9 @@ function clampVolume2(volume) {
|
|
|
11622
14231
|
function usePosterTexture2(id, poster, onError) {
|
|
11623
14232
|
const gl = useThree24((state) => state.gl);
|
|
11624
14233
|
const [texture, setTexture] = useState17(null);
|
|
11625
|
-
const onErrorRef =
|
|
14234
|
+
const onErrorRef = useRef33(onError);
|
|
11626
14235
|
onErrorRef.current = onError;
|
|
11627
|
-
|
|
14236
|
+
useEffect34(() => {
|
|
11628
14237
|
let active = true;
|
|
11629
14238
|
setTexture(null);
|
|
11630
14239
|
if (!poster) {
|
|
@@ -11661,7 +14270,7 @@ function usePosterTexture2(id, poster, onError) {
|
|
|
11661
14270
|
active = false;
|
|
11662
14271
|
};
|
|
11663
14272
|
}, [gl, id, poster]);
|
|
11664
|
-
|
|
14273
|
+
useEffect34(
|
|
11665
14274
|
() => () => {
|
|
11666
14275
|
texture?.dispose();
|
|
11667
14276
|
},
|
|
@@ -11680,13 +14289,13 @@ function useVideoResource({
|
|
|
11680
14289
|
src
|
|
11681
14290
|
}) {
|
|
11682
14291
|
const [resource, setResource] = useState17(null);
|
|
11683
|
-
const onEndedRef =
|
|
11684
|
-
const onErrorRef =
|
|
11685
|
-
const onPlaybackStateChangeRef =
|
|
14292
|
+
const onEndedRef = useRef33(onEnded);
|
|
14293
|
+
const onErrorRef = useRef33(onError);
|
|
14294
|
+
const onPlaybackStateChangeRef = useRef33(onPlaybackStateChange);
|
|
11686
14295
|
onEndedRef.current = onEnded;
|
|
11687
14296
|
onErrorRef.current = onError;
|
|
11688
14297
|
onPlaybackStateChangeRef.current = onPlaybackStateChange;
|
|
11689
|
-
|
|
14298
|
+
useEffect34(() => {
|
|
11690
14299
|
if (!src) {
|
|
11691
14300
|
setResource(null);
|
|
11692
14301
|
return;
|
|
@@ -11787,11 +14396,11 @@ function VideoHotspot({
|
|
|
11787
14396
|
src
|
|
11788
14397
|
});
|
|
11789
14398
|
const posterTexture = usePosterTexture2(id, poster, onError);
|
|
11790
|
-
const onPlaybackErrorRef =
|
|
11791
|
-
const onPlaybackStateChangeRef =
|
|
14399
|
+
const onPlaybackErrorRef = useRef33(onPlaybackError);
|
|
14400
|
+
const onPlaybackStateChangeRef = useRef33(onPlaybackStateChange);
|
|
11792
14401
|
onPlaybackErrorRef.current = onPlaybackError;
|
|
11793
14402
|
onPlaybackStateChangeRef.current = onPlaybackStateChange;
|
|
11794
|
-
|
|
14403
|
+
useEffect34(() => {
|
|
11795
14404
|
if (!resource) {
|
|
11796
14405
|
return;
|
|
11797
14406
|
}
|
|
@@ -11801,7 +14410,7 @@ function VideoHotspot({
|
|
|
11801
14410
|
resource.video.playsInline = playsInline;
|
|
11802
14411
|
resource.video.preload = preload;
|
|
11803
14412
|
}, [loop, muted, playsInline, preload, resource, volume]);
|
|
11804
|
-
|
|
14413
|
+
useEffect34(() => {
|
|
11805
14414
|
if (!resource) {
|
|
11806
14415
|
return;
|
|
11807
14416
|
}
|
|
@@ -11827,16 +14436,314 @@ function VideoHotspot({
|
|
|
11827
14436
|
return /* @__PURE__ */ jsx33(HotspotAnchor, { ...anchorProps, id, height, width, children: /* @__PURE__ */ jsx33(HotspotPlane, { map: activeTexture, opacity }) });
|
|
11828
14437
|
}
|
|
11829
14438
|
|
|
11830
|
-
// src/hotspot/
|
|
11831
|
-
import {
|
|
14439
|
+
// src/hotspot/audio-hotspot.tsx
|
|
14440
|
+
import { useFrame as useFrame16, useThree as useThree25 } from "@react-three/fiber";
|
|
14441
|
+
import { useEffect as useEffect35, useRef as useRef34, useState as useState18 } from "react";
|
|
11832
14442
|
import {
|
|
11833
14443
|
CanvasTexture as CanvasTexture2,
|
|
11834
14444
|
ClampToEdgeWrapping as ClampToEdgeWrapping7,
|
|
11835
14445
|
LinearFilter as LinearFilter10,
|
|
11836
14446
|
LinearMipmapLinearFilter as LinearMipmapLinearFilter7,
|
|
11837
|
-
SRGBColorSpace as SRGBColorSpace9
|
|
14447
|
+
SRGBColorSpace as SRGBColorSpace9,
|
|
14448
|
+
TextureLoader as TextureLoader8
|
|
11838
14449
|
} from "three";
|
|
11839
14450
|
import { jsx as jsx34 } from "react/jsx-runtime";
|
|
14451
|
+
var SPEAKER_TEXTURE_SIZE = 512;
|
|
14452
|
+
function paintSpeakerBody(context, center) {
|
|
14453
|
+
context.fillStyle = "#f5fbfc";
|
|
14454
|
+
context.beginPath();
|
|
14455
|
+
context.moveTo(center - 92, center - 36);
|
|
14456
|
+
context.lineTo(center - 28, center - 36);
|
|
14457
|
+
context.lineTo(center + 28, center - 96);
|
|
14458
|
+
context.lineTo(center + 28, center + 96);
|
|
14459
|
+
context.lineTo(center - 28, center + 36);
|
|
14460
|
+
context.lineTo(center - 92, center + 36);
|
|
14461
|
+
context.closePath();
|
|
14462
|
+
context.fill();
|
|
14463
|
+
}
|
|
14464
|
+
function createSpeakerTexture(state) {
|
|
14465
|
+
const canvas = document.createElement("canvas");
|
|
14466
|
+
canvas.width = SPEAKER_TEXTURE_SIZE;
|
|
14467
|
+
canvas.height = SPEAKER_TEXTURE_SIZE;
|
|
14468
|
+
const context = canvas.getContext("2d");
|
|
14469
|
+
if (!context) {
|
|
14470
|
+
throw new Error("Canvas 2D is unavailable for this audio hotspot.");
|
|
14471
|
+
}
|
|
14472
|
+
const center = SPEAKER_TEXTURE_SIZE / 2;
|
|
14473
|
+
context.clearRect(0, 0, SPEAKER_TEXTURE_SIZE, SPEAKER_TEXTURE_SIZE);
|
|
14474
|
+
context.lineJoin = "round";
|
|
14475
|
+
context.lineCap = "round";
|
|
14476
|
+
context.beginPath();
|
|
14477
|
+
context.arc(center, center, center - 18, 0, Math.PI * 2);
|
|
14478
|
+
context.fillStyle = state === "playing" ? "#df6b42" : "#1a3a40";
|
|
14479
|
+
context.fill();
|
|
14480
|
+
context.strokeStyle = "#f5fbfc";
|
|
14481
|
+
context.lineWidth = 22;
|
|
14482
|
+
context.stroke();
|
|
14483
|
+
paintSpeakerBody(context, center);
|
|
14484
|
+
context.strokeStyle = "#f5fbfc";
|
|
14485
|
+
context.lineWidth = 18;
|
|
14486
|
+
switch (state) {
|
|
14487
|
+
case "stopped":
|
|
14488
|
+
break;
|
|
14489
|
+
case "playing": {
|
|
14490
|
+
context.beginPath();
|
|
14491
|
+
context.arc(center + 44, center, 44, -Math.PI / 2.6, Math.PI / 2.6);
|
|
14492
|
+
context.stroke();
|
|
14493
|
+
context.beginPath();
|
|
14494
|
+
context.arc(center + 44, center, 78, -Math.PI / 2.8, Math.PI / 2.8);
|
|
14495
|
+
context.stroke();
|
|
14496
|
+
break;
|
|
14497
|
+
}
|
|
14498
|
+
default: {
|
|
14499
|
+
const exhaustive = state;
|
|
14500
|
+
return exhaustive;
|
|
14501
|
+
}
|
|
14502
|
+
}
|
|
14503
|
+
const texture = new CanvasTexture2(canvas);
|
|
14504
|
+
texture.colorSpace = SRGBColorSpace9;
|
|
14505
|
+
texture.wrapS = ClampToEdgeWrapping7;
|
|
14506
|
+
texture.wrapT = ClampToEdgeWrapping7;
|
|
14507
|
+
texture.magFilter = LinearFilter10;
|
|
14508
|
+
texture.minFilter = LinearMipmapLinearFilter7;
|
|
14509
|
+
texture.generateMipmaps = true;
|
|
14510
|
+
texture.needsUpdate = true;
|
|
14511
|
+
return texture;
|
|
14512
|
+
}
|
|
14513
|
+
function useSpeakerTextures(enabled) {
|
|
14514
|
+
const [textures, setTextures] = useState18({ playing: null, stopped: null });
|
|
14515
|
+
useEffect35(() => {
|
|
14516
|
+
if (!enabled) {
|
|
14517
|
+
setTextures({ playing: null, stopped: null });
|
|
14518
|
+
return;
|
|
14519
|
+
}
|
|
14520
|
+
const playing = createSpeakerTexture("playing");
|
|
14521
|
+
const stopped = createSpeakerTexture("stopped");
|
|
14522
|
+
setTextures({ playing, stopped });
|
|
14523
|
+
return () => {
|
|
14524
|
+
playing.dispose();
|
|
14525
|
+
stopped.dispose();
|
|
14526
|
+
};
|
|
14527
|
+
}, [enabled]);
|
|
14528
|
+
return textures;
|
|
14529
|
+
}
|
|
14530
|
+
function useIconTexture(icon, enabled, onError, id) {
|
|
14531
|
+
const gl = useThree25((state) => state.gl);
|
|
14532
|
+
const [texture, setTexture] = useState18(null);
|
|
14533
|
+
const onErrorRef = useRef34(onError);
|
|
14534
|
+
onErrorRef.current = onError;
|
|
14535
|
+
useEffect35(() => {
|
|
14536
|
+
let active = true;
|
|
14537
|
+
setTexture(null);
|
|
14538
|
+
if (!enabled || !icon) {
|
|
14539
|
+
return () => {
|
|
14540
|
+
active = false;
|
|
14541
|
+
};
|
|
14542
|
+
}
|
|
14543
|
+
const loader = new TextureLoader8();
|
|
14544
|
+
loader.load(
|
|
14545
|
+
icon,
|
|
14546
|
+
(loadedTexture) => {
|
|
14547
|
+
if (!active) {
|
|
14548
|
+
loadedTexture.dispose();
|
|
14549
|
+
return;
|
|
14550
|
+
}
|
|
14551
|
+
loadedTexture.colorSpace = SRGBColorSpace9;
|
|
14552
|
+
loadedTexture.wrapS = ClampToEdgeWrapping7;
|
|
14553
|
+
loadedTexture.wrapT = ClampToEdgeWrapping7;
|
|
14554
|
+
loadedTexture.magFilter = LinearFilter10;
|
|
14555
|
+
loadedTexture.minFilter = LinearMipmapLinearFilter7;
|
|
14556
|
+
loadedTexture.generateMipmaps = true;
|
|
14557
|
+
loadedTexture.anisotropy = gl.capabilities.getMaxAnisotropy();
|
|
14558
|
+
loadedTexture.needsUpdate = true;
|
|
14559
|
+
setTexture(loadedTexture);
|
|
14560
|
+
},
|
|
14561
|
+
void 0,
|
|
14562
|
+
(error) => {
|
|
14563
|
+
if (active) {
|
|
14564
|
+
onErrorRef.current?.({ id, error });
|
|
14565
|
+
}
|
|
14566
|
+
}
|
|
14567
|
+
);
|
|
14568
|
+
return () => {
|
|
14569
|
+
active = false;
|
|
14570
|
+
};
|
|
14571
|
+
}, [enabled, gl, icon, id]);
|
|
14572
|
+
useEffect35(
|
|
14573
|
+
() => () => {
|
|
14574
|
+
texture?.dispose();
|
|
14575
|
+
},
|
|
14576
|
+
[texture]
|
|
14577
|
+
);
|
|
14578
|
+
return texture;
|
|
14579
|
+
}
|
|
14580
|
+
function useAudioHowl({
|
|
14581
|
+
crossOrigin,
|
|
14582
|
+
id,
|
|
14583
|
+
loop,
|
|
14584
|
+
onEnded,
|
|
14585
|
+
onError,
|
|
14586
|
+
onPlaybackError,
|
|
14587
|
+
onPlaybackStateChange,
|
|
14588
|
+
playing,
|
|
14589
|
+
src
|
|
14590
|
+
}) {
|
|
14591
|
+
const [howl, setHowl] = useState18(null);
|
|
14592
|
+
const playingRef = useRef34(playing);
|
|
14593
|
+
const loopRef = useRef34(loop ?? false);
|
|
14594
|
+
const onEndedRef = useRef34(onEnded);
|
|
14595
|
+
const onErrorRef = useRef34(onError);
|
|
14596
|
+
const onPlaybackErrorRef = useRef34(onPlaybackError);
|
|
14597
|
+
const onPlaybackStateChangeRef = useRef34(onPlaybackStateChange);
|
|
14598
|
+
playingRef.current = playing;
|
|
14599
|
+
loopRef.current = loop ?? false;
|
|
14600
|
+
onEndedRef.current = onEnded;
|
|
14601
|
+
onErrorRef.current = onError;
|
|
14602
|
+
onPlaybackErrorRef.current = onPlaybackError;
|
|
14603
|
+
onPlaybackStateChangeRef.current = onPlaybackStateChange;
|
|
14604
|
+
const sourcesKey = sourceList(src).join("\0");
|
|
14605
|
+
useEffect35(() => {
|
|
14606
|
+
const sources = sourcesKey.length > 0 ? sourcesKey.split("\0") : [];
|
|
14607
|
+
if (sources.length === 0) {
|
|
14608
|
+
setHowl(null);
|
|
14609
|
+
return;
|
|
14610
|
+
}
|
|
14611
|
+
let active = true;
|
|
14612
|
+
const handle = createUnlockingHowl({
|
|
14613
|
+
src: sources,
|
|
14614
|
+
loop: loopRef.current,
|
|
14615
|
+
crossOrigin,
|
|
14616
|
+
isActive: () => active,
|
|
14617
|
+
shouldRetryPlay: () => playingRef.current,
|
|
14618
|
+
onEnded: () => {
|
|
14619
|
+
onPlaybackStateChangeRef.current?.("ended");
|
|
14620
|
+
onEndedRef.current?.();
|
|
14621
|
+
},
|
|
14622
|
+
onPlay: () => {
|
|
14623
|
+
onPlaybackStateChangeRef.current?.("playing");
|
|
14624
|
+
},
|
|
14625
|
+
onPause: () => {
|
|
14626
|
+
onPlaybackStateChangeRef.current?.("paused");
|
|
14627
|
+
},
|
|
14628
|
+
onLoadError: (error) => {
|
|
14629
|
+
onErrorRef.current?.({ id, error });
|
|
14630
|
+
},
|
|
14631
|
+
onPlayError: (error) => {
|
|
14632
|
+
onPlaybackStateChangeRef.current?.("blocked");
|
|
14633
|
+
onPlaybackErrorRef.current?.(error);
|
|
14634
|
+
}
|
|
14635
|
+
});
|
|
14636
|
+
setHowl(handle.howl);
|
|
14637
|
+
return () => {
|
|
14638
|
+
active = false;
|
|
14639
|
+
handle.dispose();
|
|
14640
|
+
};
|
|
14641
|
+
}, [crossOrigin, id, sourcesKey]);
|
|
14642
|
+
useEffect35(() => {
|
|
14643
|
+
howl?.loop(loop ?? false);
|
|
14644
|
+
}, [howl, loop]);
|
|
14645
|
+
return howl;
|
|
14646
|
+
}
|
|
14647
|
+
function AudioHotspot({
|
|
14648
|
+
id,
|
|
14649
|
+
src,
|
|
14650
|
+
playing,
|
|
14651
|
+
loop = false,
|
|
14652
|
+
muted = false,
|
|
14653
|
+
volume = 1,
|
|
14654
|
+
range = 360,
|
|
14655
|
+
pauseWhenHidden = true,
|
|
14656
|
+
icon,
|
|
14657
|
+
playingIcon,
|
|
14658
|
+
marker = true,
|
|
14659
|
+
crossOrigin,
|
|
14660
|
+
width = 8,
|
|
14661
|
+
height = 8,
|
|
14662
|
+
opacity,
|
|
14663
|
+
onPlaybackStateChange,
|
|
14664
|
+
onPlaybackError,
|
|
14665
|
+
onEnded,
|
|
14666
|
+
onError,
|
|
14667
|
+
...anchorProps
|
|
14668
|
+
}) {
|
|
14669
|
+
const camera = useThree25((state) => state.camera);
|
|
14670
|
+
const howl = useAudioHowl({
|
|
14671
|
+
crossOrigin,
|
|
14672
|
+
id,
|
|
14673
|
+
loop,
|
|
14674
|
+
onEnded,
|
|
14675
|
+
onError,
|
|
14676
|
+
onPlaybackError,
|
|
14677
|
+
onPlaybackStateChange,
|
|
14678
|
+
playing,
|
|
14679
|
+
src
|
|
14680
|
+
});
|
|
14681
|
+
const speakerTextures = useSpeakerTextures(marker && !icon);
|
|
14682
|
+
const stoppedIconTexture = useIconTexture(icon, marker, onError, id);
|
|
14683
|
+
const playingIconTexture = useIconTexture(playingIcon, marker, onError, id);
|
|
14684
|
+
const markerTexture = playing ? playingIconTexture ?? stoppedIconTexture ?? speakerTextures.playing : stoppedIconTexture ?? speakerTextures.stopped;
|
|
14685
|
+
const playingRef = useRef34(playing);
|
|
14686
|
+
playingRef.current = playing;
|
|
14687
|
+
const mutedRef = useRef34(muted);
|
|
14688
|
+
const volumeRef = useRef34(volume);
|
|
14689
|
+
const rangeRef = useRef34(range);
|
|
14690
|
+
mutedRef.current = muted;
|
|
14691
|
+
volumeRef.current = volume;
|
|
14692
|
+
rangeRef.current = range;
|
|
14693
|
+
useEffect35(() => {
|
|
14694
|
+
if (!howl) {
|
|
14695
|
+
return;
|
|
14696
|
+
}
|
|
14697
|
+
if (!playing) {
|
|
14698
|
+
howl.pause();
|
|
14699
|
+
return;
|
|
14700
|
+
}
|
|
14701
|
+
howl.play();
|
|
14702
|
+
}, [howl, playing]);
|
|
14703
|
+
useEffect35(() => {
|
|
14704
|
+
if (!howl || !pauseWhenHidden) {
|
|
14705
|
+
return;
|
|
14706
|
+
}
|
|
14707
|
+
const handleVisibility = () => {
|
|
14708
|
+
if (document.hidden) {
|
|
14709
|
+
howl.pause();
|
|
14710
|
+
return;
|
|
14711
|
+
}
|
|
14712
|
+
if (playingRef.current) {
|
|
14713
|
+
howl.play();
|
|
14714
|
+
}
|
|
14715
|
+
};
|
|
14716
|
+
document.addEventListener("visibilitychange", handleVisibility);
|
|
14717
|
+
return () => {
|
|
14718
|
+
document.removeEventListener("visibilitychange", handleVisibility);
|
|
14719
|
+
};
|
|
14720
|
+
}, [howl, pauseWhenHidden]);
|
|
14721
|
+
useFrame16(() => {
|
|
14722
|
+
if (!howl) {
|
|
14723
|
+
return;
|
|
14724
|
+
}
|
|
14725
|
+
const spatial = audioSpatialFromView(
|
|
14726
|
+
camera,
|
|
14727
|
+
anchorProps.position,
|
|
14728
|
+
clampLookRange(rangeRef.current)
|
|
14729
|
+
);
|
|
14730
|
+
howl.stereo(spatial.pan);
|
|
14731
|
+
howl.mute(mutedRef.current);
|
|
14732
|
+
howl.volume(clampAudioVolume(volumeRef.current) * spatial.gain);
|
|
14733
|
+
});
|
|
14734
|
+
return /* @__PURE__ */ jsx34(HotspotAnchor, { ...anchorProps, id, height, width, children: marker ? /* @__PURE__ */ jsx34(HotspotPlane, { map: markerTexture, opacity }) : null });
|
|
14735
|
+
}
|
|
14736
|
+
|
|
14737
|
+
// src/hotspot/text-hotspot.tsx
|
|
14738
|
+
import { useEffect as useEffect36, useRef as useRef35, useState as useState19 } from "react";
|
|
14739
|
+
import {
|
|
14740
|
+
CanvasTexture as CanvasTexture3,
|
|
14741
|
+
ClampToEdgeWrapping as ClampToEdgeWrapping8,
|
|
14742
|
+
LinearFilter as LinearFilter11,
|
|
14743
|
+
LinearMipmapLinearFilter as LinearMipmapLinearFilter8,
|
|
14744
|
+
SRGBColorSpace as SRGBColorSpace10
|
|
14745
|
+
} from "three";
|
|
14746
|
+
import { jsx as jsx35 } from "react/jsx-runtime";
|
|
11840
14747
|
var TEXT_TEXTURE_LONG_SIDE = 1024;
|
|
11841
14748
|
var DEFAULT_FONT_FAMILY = "system-ui, sans-serif";
|
|
11842
14749
|
var DEFAULT_FONT_SIZE = 96;
|
|
@@ -12045,23 +14952,23 @@ function createTextTexture(text, width, height, style) {
|
|
|
12045
14952
|
throw new Error("Canvas 2D is unavailable for this text hotspot.");
|
|
12046
14953
|
}
|
|
12047
14954
|
drawTextHotspot(context, canvasWidth, canvasHeight, text, style);
|
|
12048
|
-
const texture = new
|
|
12049
|
-
texture.colorSpace =
|
|
12050
|
-
texture.wrapS =
|
|
12051
|
-
texture.wrapT =
|
|
12052
|
-
texture.magFilter =
|
|
12053
|
-
texture.minFilter =
|
|
14955
|
+
const texture = new CanvasTexture3(canvas);
|
|
14956
|
+
texture.colorSpace = SRGBColorSpace10;
|
|
14957
|
+
texture.wrapS = ClampToEdgeWrapping8;
|
|
14958
|
+
texture.wrapT = ClampToEdgeWrapping8;
|
|
14959
|
+
texture.magFilter = LinearFilter11;
|
|
14960
|
+
texture.minFilter = LinearMipmapLinearFilter8;
|
|
12054
14961
|
texture.generateMipmaps = true;
|
|
12055
14962
|
texture.needsUpdate = true;
|
|
12056
14963
|
return texture;
|
|
12057
14964
|
}
|
|
12058
14965
|
function useTextTexture(text, width, height, style, onLoad, onError) {
|
|
12059
|
-
const [texture, setTexture] =
|
|
12060
|
-
const onLoadRef =
|
|
12061
|
-
const onErrorRef =
|
|
14966
|
+
const [texture, setTexture] = useState19(null);
|
|
14967
|
+
const onLoadRef = useRef35(onLoad);
|
|
14968
|
+
const onErrorRef = useRef35(onError);
|
|
12062
14969
|
onLoadRef.current = onLoad;
|
|
12063
14970
|
onErrorRef.current = onError;
|
|
12064
|
-
|
|
14971
|
+
useEffect36(() => {
|
|
12065
14972
|
let cancelled = false;
|
|
12066
14973
|
let nextTexture = null;
|
|
12067
14974
|
const run = async () => {
|
|
@@ -12154,13 +15061,13 @@ function TextHotspot({
|
|
|
12154
15061
|
whiteSpace
|
|
12155
15062
|
};
|
|
12156
15063
|
const texture = useTextTexture(text, width, height, style, onLoad, onError);
|
|
12157
|
-
return /* @__PURE__ */
|
|
15064
|
+
return /* @__PURE__ */ jsx35(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx35(HotspotPlane, { map: texture, opacity }) });
|
|
12158
15065
|
}
|
|
12159
15066
|
|
|
12160
15067
|
// src/hotspot/iframe-hotspot.tsx
|
|
12161
15068
|
import { Html as Html2 } from "@react-three/drei";
|
|
12162
15069
|
import { DoubleSide as DoubleSide6 } from "three";
|
|
12163
|
-
import { jsx as
|
|
15070
|
+
import { jsx as jsx36, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
12164
15071
|
var IFRAME_LONG_SIDE = 800;
|
|
12165
15072
|
var CSS3D_DISTANCE_FACTOR = 400;
|
|
12166
15073
|
var DEFAULT_SANDBOX = "allow-scripts allow-popups allow-forms";
|
|
@@ -12227,8 +15134,8 @@ function IframeHotspot({
|
|
|
12227
15134
|
width,
|
|
12228
15135
|
children: [
|
|
12229
15136
|
/* @__PURE__ */ jsxs19("mesh", { children: [
|
|
12230
|
-
/* @__PURE__ */
|
|
12231
|
-
/* @__PURE__ */
|
|
15137
|
+
/* @__PURE__ */ jsx36("planeGeometry", { args: [1, 1] }),
|
|
15138
|
+
/* @__PURE__ */ jsx36(
|
|
12232
15139
|
"meshBasicMaterial",
|
|
12233
15140
|
{
|
|
12234
15141
|
depthWrite: false,
|
|
@@ -12239,7 +15146,7 @@ function IframeHotspot({
|
|
|
12239
15146
|
}
|
|
12240
15147
|
)
|
|
12241
15148
|
] }),
|
|
12242
|
-
/* @__PURE__ */
|
|
15149
|
+
/* @__PURE__ */ jsx36(
|
|
12243
15150
|
Html2,
|
|
12244
15151
|
{
|
|
12245
15152
|
distanceFactor: CSS3D_DISTANCE_FACTOR,
|
|
@@ -12254,7 +15161,7 @@ function IframeHotspot({
|
|
|
12254
15161
|
},
|
|
12255
15162
|
transform: true,
|
|
12256
15163
|
zIndexRange: [10, 0],
|
|
12257
|
-
children: /* @__PURE__ */
|
|
15164
|
+
children: /* @__PURE__ */ jsx36(
|
|
12258
15165
|
"iframe",
|
|
12259
15166
|
{
|
|
12260
15167
|
allow,
|
|
@@ -12275,7 +15182,9 @@ function IframeHotspot({
|
|
|
12275
15182
|
);
|
|
12276
15183
|
}
|
|
12277
15184
|
export {
|
|
15185
|
+
AudioHotspot,
|
|
12278
15186
|
AutoRotate,
|
|
15187
|
+
BackgroundAudio,
|
|
12279
15188
|
DEFAULT_HOTSPOT_TOOLTIP_APPEARANCE,
|
|
12280
15189
|
DEFAULT_HOTSPOT_TOOLTIP_OFFSET,
|
|
12281
15190
|
DEFAULT_PANO_CURSORS,
|
|
@@ -12326,4 +15235,28 @@ export {
|
|
|
12326
15235
|
validatePolylineVertices,
|
|
12327
15236
|
vector3ToPanoPosition
|
|
12328
15237
|
};
|
|
15238
|
+
/*! Bundled license information:
|
|
15239
|
+
|
|
15240
|
+
howler/dist/howler.js:
|
|
15241
|
+
(*!
|
|
15242
|
+
* howler.js v2.2.4
|
|
15243
|
+
* howlerjs.com
|
|
15244
|
+
*
|
|
15245
|
+
* (c) 2013-2020, James Simpson of GoldFire Studios
|
|
15246
|
+
* goldfirestudios.com
|
|
15247
|
+
*
|
|
15248
|
+
* MIT License
|
|
15249
|
+
*)
|
|
15250
|
+
(*!
|
|
15251
|
+
* Spatial Plugin - Adds support for stereo and 3D audio where Web Audio is supported.
|
|
15252
|
+
*
|
|
15253
|
+
* howler.js v2.2.4
|
|
15254
|
+
* howlerjs.com
|
|
15255
|
+
*
|
|
15256
|
+
* (c) 2013-2020, James Simpson of GoldFire Studios
|
|
15257
|
+
* goldfirestudios.com
|
|
15258
|
+
*
|
|
15259
|
+
* MIT License
|
|
15260
|
+
*)
|
|
15261
|
+
*/
|
|
12329
15262
|
//# sourceMappingURL=index.mjs.map
|