@ericchen1990/pano-view 2.2.1 → 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 +126 -7
- package/README.zh-CN.md +87 -3
- package/dist/index.cjs +3489 -560
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +80 -4
- package/dist/index.d.ts +80 -4
- package/dist/index.mjs +3280 -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";
|
|
@@ -4576,6 +6814,19 @@ var PanoViewer = forwardRef2(
|
|
|
4576
6814
|
syncFullscreen();
|
|
4577
6815
|
return subscribeFullscreenChange(syncFullscreen);
|
|
4578
6816
|
}, []);
|
|
6817
|
+
useEffect12(() => {
|
|
6818
|
+
const root = rootRef.current;
|
|
6819
|
+
if (!root) {
|
|
6820
|
+
return;
|
|
6821
|
+
}
|
|
6822
|
+
const suppressNativeContextMenu = (event) => {
|
|
6823
|
+
event.preventDefault();
|
|
6824
|
+
};
|
|
6825
|
+
root.addEventListener("contextmenu", suppressNativeContextMenu, true);
|
|
6826
|
+
return () => {
|
|
6827
|
+
root.removeEventListener("contextmenu", suppressNativeContextMenu, true);
|
|
6828
|
+
};
|
|
6829
|
+
}, []);
|
|
4579
6830
|
const contextMenuActions = useMemo7(
|
|
4580
6831
|
() => ({
|
|
4581
6832
|
reset: () => {
|
|
@@ -4758,14 +7009,385 @@ var PanoViewer = forwardRef2(
|
|
|
4758
7009
|
}
|
|
4759
7010
|
);
|
|
4760
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
|
+
|
|
4761
7383
|
// src/pano-filter/pano-filter.tsx
|
|
4762
|
-
import { useContext as
|
|
7384
|
+
import { useContext as useContext16, useEffect as useEffect14, useMemo as useMemo8 } from "react";
|
|
4763
7385
|
function PanoFilter({
|
|
4764
7386
|
preset = "none",
|
|
4765
7387
|
intensity,
|
|
4766
7388
|
enabled = true
|
|
4767
7389
|
}) {
|
|
4768
|
-
const host =
|
|
7390
|
+
const host = useContext16(PanoFilterHostContext);
|
|
4769
7391
|
if (!host) {
|
|
4770
7392
|
throw new Error("<PanoFilter> must be rendered inside <PanoViewer>.");
|
|
4771
7393
|
}
|
|
@@ -4773,13 +7395,13 @@ function PanoFilter({
|
|
|
4773
7395
|
() => resolvePanoFilterSnapshot({ preset, intensity, enabled }),
|
|
4774
7396
|
[enabled, intensity, preset]
|
|
4775
7397
|
);
|
|
4776
|
-
|
|
7398
|
+
useEffect14(() => {
|
|
4777
7399
|
claimPanoFilter(host);
|
|
4778
7400
|
return () => {
|
|
4779
7401
|
releasePanoFilter(host);
|
|
4780
7402
|
};
|
|
4781
7403
|
}, [host]);
|
|
4782
|
-
|
|
7404
|
+
useEffect14(() => {
|
|
4783
7405
|
setPanoFilterSnapshot(host, snapshot);
|
|
4784
7406
|
}, [host, snapshot]);
|
|
4785
7407
|
return null;
|
|
@@ -4790,20 +7412,20 @@ import { useFrame as useFrame6, useThree as useThree9 } from "@react-three/fiber
|
|
|
4790
7412
|
import {
|
|
4791
7413
|
forwardRef as forwardRef3,
|
|
4792
7414
|
useCallback as useCallback7,
|
|
4793
|
-
useContext as
|
|
4794
|
-
useEffect as
|
|
7415
|
+
useContext as useContext17,
|
|
7416
|
+
useEffect as useEffect15,
|
|
4795
7417
|
useImperativeHandle as useImperativeHandle3,
|
|
4796
|
-
useRef as
|
|
7418
|
+
useRef as useRef14,
|
|
4797
7419
|
useState as useState6
|
|
4798
7420
|
} from "react";
|
|
4799
7421
|
|
|
4800
7422
|
// src/gyro-orientation.ts
|
|
4801
|
-
import { Euler as Euler2, MathUtils as
|
|
7423
|
+
import { Euler as Euler2, MathUtils as MathUtils4, Quaternion, Vector3 as Vector36 } from "three";
|
|
4802
7424
|
var DEVICE_FORWARD_CORRECTION = new Quaternion().setFromAxisAngle(
|
|
4803
|
-
new
|
|
7425
|
+
new Vector36(1, 0, 0),
|
|
4804
7426
|
-Math.PI / 2
|
|
4805
7427
|
);
|
|
4806
|
-
var SCREEN_AXIS = new
|
|
7428
|
+
var SCREEN_AXIS = new Vector36(0, 0, 1);
|
|
4807
7429
|
function getScreenOrientationAngle() {
|
|
4808
7430
|
if (typeof window === "undefined") {
|
|
4809
7431
|
return 0;
|
|
@@ -4818,30 +7440,30 @@ function getScreenOrientationAngle() {
|
|
|
4818
7440
|
function deviceOrientationToQuaternion(sample, screenOrientation) {
|
|
4819
7441
|
const alpha = Number.isFinite(sample.compassHeading) ? 360 - sample.compassHeading : sample.alpha;
|
|
4820
7442
|
const deviceEuler = new Euler2(
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
7443
|
+
MathUtils4.degToRad(sample.beta),
|
|
7444
|
+
MathUtils4.degToRad(alpha),
|
|
7445
|
+
MathUtils4.degToRad(-sample.gamma),
|
|
4824
7446
|
"YXZ"
|
|
4825
7447
|
);
|
|
4826
7448
|
const screenCorrection = new Quaternion().setFromAxisAngle(
|
|
4827
7449
|
SCREEN_AXIS,
|
|
4828
|
-
-
|
|
7450
|
+
-MathUtils4.degToRad(screenOrientation)
|
|
4829
7451
|
);
|
|
4830
7452
|
return new Quaternion().setFromEuler(deviceEuler).multiply(DEVICE_FORWARD_CORRECTION).multiply(screenCorrection).normalize();
|
|
4831
7453
|
}
|
|
4832
7454
|
function quaternionToGyroPose(quaternion) {
|
|
4833
7455
|
const euler = new Euler2().setFromQuaternion(quaternion, "YXZ");
|
|
4834
7456
|
return {
|
|
4835
|
-
yaw:
|
|
4836
|
-
pitch:
|
|
4837
|
-
roll:
|
|
7457
|
+
yaw: MathUtils4.radToDeg(-euler.y),
|
|
7458
|
+
pitch: MathUtils4.radToDeg(euler.x),
|
|
7459
|
+
roll: MathUtils4.radToDeg(euler.z)
|
|
4838
7460
|
};
|
|
4839
7461
|
}
|
|
4840
7462
|
function createRelativeCalibration(deviceQuaternion, yaw, pitch) {
|
|
4841
7463
|
const targetQuaternion = new Quaternion().setFromEuler(
|
|
4842
7464
|
new Euler2(
|
|
4843
|
-
|
|
4844
|
-
|
|
7465
|
+
MathUtils4.degToRad(pitch),
|
|
7466
|
+
MathUtils4.degToRad(-yaw),
|
|
4845
7467
|
0,
|
|
4846
7468
|
"YXZ"
|
|
4847
7469
|
)
|
|
@@ -4895,24 +7517,24 @@ var Gyro = forwardRef3(function Gyro2({
|
|
|
4895
7517
|
onDisable,
|
|
4896
7518
|
onDenied
|
|
4897
7519
|
}, ref) {
|
|
4898
|
-
const controlsRef =
|
|
4899
|
-
const eventBus =
|
|
7520
|
+
const controlsRef = useContext17(PanoramaViewContext);
|
|
7521
|
+
const eventBus = useContext17(PanoEventBusContext);
|
|
4900
7522
|
const { gl } = useThree9();
|
|
4901
7523
|
const [internallyDisabled, setInternallyDisabled] = useState6(false);
|
|
4902
|
-
const availableRef =
|
|
4903
|
-
const availabilityReportedRef =
|
|
4904
|
-
const activeRef =
|
|
4905
|
-
const permissionRef =
|
|
4906
|
-
const absoluteEventSourceRef =
|
|
4907
|
-
const rawQuaternionRef =
|
|
4908
|
-
const calibrationRef =
|
|
4909
|
-
const absoluteOffsetRef =
|
|
4910
|
-
const screenAngleRef =
|
|
4911
|
-
const startPoseRef =
|
|
4912
|
-
const enabledAtRef =
|
|
4913
|
-
const filteredPoseRef =
|
|
4914
|
-
const lastAppliedPoseRef =
|
|
4915
|
-
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({
|
|
4916
7538
|
onAvailable,
|
|
4917
7539
|
onUnavailable,
|
|
4918
7540
|
onEnable,
|
|
@@ -5057,22 +7679,22 @@ var Gyro = forwardRef3(function Gyro2({
|
|
|
5057
7679
|
}),
|
|
5058
7680
|
[requestPermission, resetSensor]
|
|
5059
7681
|
);
|
|
5060
|
-
|
|
7682
|
+
useEffect15(() => {
|
|
5061
7683
|
if (!enabled) {
|
|
5062
7684
|
setInternallyDisabled(false);
|
|
5063
7685
|
}
|
|
5064
7686
|
}, [enabled]);
|
|
5065
|
-
|
|
7687
|
+
useEffect15(() => {
|
|
5066
7688
|
const supported = typeof window !== "undefined" && window.isSecureContext && typeof DeviceOrientationEvent !== "undefined" && (desktopSupport || isMobileDevice());
|
|
5067
7689
|
setAvailable(supported);
|
|
5068
7690
|
return () => {
|
|
5069
7691
|
availableRef.current = false;
|
|
5070
7692
|
};
|
|
5071
7693
|
}, [desktopSupport, setAvailable]);
|
|
5072
|
-
|
|
7694
|
+
useEffect15(() => {
|
|
5073
7695
|
controlsRef.current?.setGyroTouchMode(touchMode);
|
|
5074
7696
|
}, [controlsRef, touchMode]);
|
|
5075
|
-
|
|
7697
|
+
useEffect15(() => {
|
|
5076
7698
|
if (!enabled || internallyDisabled || touchMode !== "disablegyro") {
|
|
5077
7699
|
return;
|
|
5078
7700
|
}
|
|
@@ -5086,7 +7708,7 @@ var Gyro = forwardRef3(function Gyro2({
|
|
|
5086
7708
|
gl.domElement.removeEventListener("pointerdown", onPointerDown);
|
|
5087
7709
|
};
|
|
5088
7710
|
}, [enabled, gl, internallyDisabled, touchMode]);
|
|
5089
|
-
|
|
7711
|
+
useEffect15(() => {
|
|
5090
7712
|
if (!enabled || internallyDisabled || !availableRef.current) {
|
|
5091
7713
|
deactivate();
|
|
5092
7714
|
return;
|
|
@@ -5251,11 +7873,11 @@ import { useThree as useThree12 } from "@react-three/fiber";
|
|
|
5251
7873
|
import {
|
|
5252
7874
|
forwardRef as forwardRef4,
|
|
5253
7875
|
useCallback as useCallback8,
|
|
5254
|
-
useContext as
|
|
5255
|
-
useEffect as
|
|
7876
|
+
useContext as useContext19,
|
|
7877
|
+
useEffect as useEffect19,
|
|
5256
7878
|
useImperativeHandle as useImperativeHandle4,
|
|
5257
7879
|
useMemo as useMemo10,
|
|
5258
|
-
useRef as
|
|
7880
|
+
useRef as useRef18,
|
|
5259
7881
|
useState as useState7
|
|
5260
7882
|
} from "react";
|
|
5261
7883
|
|
|
@@ -5280,12 +7902,12 @@ async function detectWebVRCapabilities() {
|
|
|
5280
7902
|
|
|
5281
7903
|
// src/webvr/reticle.tsx
|
|
5282
7904
|
import { useFrame as useFrame7, useThree as useThree10 } from "@react-three/fiber";
|
|
5283
|
-
import { useRef as
|
|
7905
|
+
import { useRef as useRef15 } from "react";
|
|
5284
7906
|
import {
|
|
5285
7907
|
DoubleSide,
|
|
5286
7908
|
Raycaster as Raycaster2,
|
|
5287
7909
|
Vector2 as Vector22,
|
|
5288
|
-
Vector3 as
|
|
7910
|
+
Vector3 as Vector37
|
|
5289
7911
|
} from "three";
|
|
5290
7912
|
import { jsx as jsx12, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
5291
7913
|
var CENTER_NDC = new Vector22(0, 0);
|
|
@@ -5371,13 +7993,13 @@ function WebVRReticle({
|
|
|
5371
7993
|
dwellMs,
|
|
5372
7994
|
visible
|
|
5373
7995
|
}) {
|
|
5374
|
-
const groupRef =
|
|
5375
|
-
const ringMeshRef =
|
|
5376
|
-
const directionRef =
|
|
5377
|
-
const raycasterRef =
|
|
5378
|
-
const hoveredRef =
|
|
5379
|
-
const dwellRef =
|
|
5380
|
-
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);
|
|
5381
8003
|
const { camera, gl, scene } = useThree10();
|
|
5382
8004
|
useFrame7((_, deltaSeconds) => {
|
|
5383
8005
|
const group = groupRef.current;
|
|
@@ -5540,7 +8162,7 @@ function WebVRReticle({
|
|
|
5540
8162
|
|
|
5541
8163
|
// src/webvr/stereo.tsx
|
|
5542
8164
|
import { useFrame as useFrame8, useThree as useThree11 } from "@react-three/fiber";
|
|
5543
|
-
import { useContext as
|
|
8165
|
+
import { useContext as useContext18, useEffect as useEffect16, useMemo as useMemo9, useRef as useRef16 } from "react";
|
|
5544
8166
|
import {
|
|
5545
8167
|
Mesh as Mesh2,
|
|
5546
8168
|
OrthographicCamera,
|
|
@@ -5626,25 +8248,25 @@ function WebVRStereoRenderer({
|
|
|
5626
8248
|
screensize
|
|
5627
8249
|
}) {
|
|
5628
8250
|
const { camera, gl } = useThree11();
|
|
5629
|
-
const runtime =
|
|
5630
|
-
const fallbackStereoRef =
|
|
8251
|
+
const runtime = useContext18(WebVRRuntimeContext);
|
|
8252
|
+
const fallbackStereoRef = useRef16(null);
|
|
5631
8253
|
if (!fallbackStereoRef.current) {
|
|
5632
8254
|
fallbackStereoRef.current = new StereoCamera2();
|
|
5633
8255
|
}
|
|
5634
8256
|
const stereo = runtime?.stereoView.stereo ?? fallbackStereoRef.current;
|
|
5635
|
-
const stereoRef =
|
|
8257
|
+
const stereoRef = useRef16(stereo);
|
|
5636
8258
|
stereoRef.current = stereo;
|
|
5637
8259
|
const resources = useMemo9(createDistortionResources, []);
|
|
5638
|
-
const drawingSizeRef =
|
|
5639
|
-
const viewportRef =
|
|
5640
|
-
const scissorRef =
|
|
5641
|
-
const originalFovRef =
|
|
5642
|
-
const stereoActiveRef =
|
|
5643
|
-
const profileRef =
|
|
5644
|
-
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);
|
|
5645
8267
|
profileRef.current = profile;
|
|
5646
8268
|
screensizeRef.current = screensize;
|
|
5647
|
-
|
|
8269
|
+
useEffect16(
|
|
5648
8270
|
() => () => {
|
|
5649
8271
|
resources.geometry.dispose();
|
|
5650
8272
|
resources.material.dispose();
|
|
@@ -5652,7 +8274,7 @@ function WebVRStereoRenderer({
|
|
|
5652
8274
|
},
|
|
5653
8275
|
[resources]
|
|
5654
8276
|
);
|
|
5655
|
-
|
|
8277
|
+
useEffect16(() => {
|
|
5656
8278
|
const originalRender = gl.render.bind(gl);
|
|
5657
8279
|
gl.render = (sceneToRender, cameraToRender) => {
|
|
5658
8280
|
if (!stereoActiveRef.current || !(cameraToRender instanceof PerspectiveCamera2)) {
|
|
@@ -5716,7 +8338,7 @@ function WebVRStereoRenderer({
|
|
|
5716
8338
|
gl.render = originalRender;
|
|
5717
8339
|
};
|
|
5718
8340
|
}, [gl, resources]);
|
|
5719
|
-
|
|
8341
|
+
useEffect16(
|
|
5720
8342
|
() => () => {
|
|
5721
8343
|
if (runtime) {
|
|
5722
8344
|
runtime.stereoView.active = false;
|
|
@@ -5751,7 +8373,7 @@ function WebVRStereoRenderer({
|
|
|
5751
8373
|
}
|
|
5752
8374
|
|
|
5753
8375
|
// src/webvr/pointerlock.ts
|
|
5754
|
-
import { useEffect as
|
|
8376
|
+
import { useEffect as useEffect17, useRef as useRef17 } from "react";
|
|
5755
8377
|
var POINTER_LOCK_CURSOR_ID = "webvr:pointerlock";
|
|
5756
8378
|
async function requestWebVRPointerLock(element) {
|
|
5757
8379
|
if (typeof document === "undefined") {
|
|
@@ -5784,11 +8406,11 @@ function exitWebVRPointerLock(element) {
|
|
|
5784
8406
|
}
|
|
5785
8407
|
function useWebVRPointerLock(enabled, element) {
|
|
5786
8408
|
const cursor = usePanoCursor();
|
|
5787
|
-
const cursorRef =
|
|
5788
|
-
const enabledRef =
|
|
8409
|
+
const cursorRef = useRef17(cursor);
|
|
8410
|
+
const enabledRef = useRef17(enabled);
|
|
5789
8411
|
cursorRef.current = cursor;
|
|
5790
8412
|
enabledRef.current = enabled;
|
|
5791
|
-
|
|
8413
|
+
useEffect17(() => {
|
|
5792
8414
|
if (!enabled || !element) {
|
|
5793
8415
|
return;
|
|
5794
8416
|
}
|
|
@@ -5818,7 +8440,7 @@ function useWebVRPointerLock(enabled, element) {
|
|
|
5818
8440
|
}
|
|
5819
8441
|
|
|
5820
8442
|
// src/webvr/wakelock.ts
|
|
5821
|
-
import { useEffect as
|
|
8443
|
+
import { useEffect as useEffect18 } from "react";
|
|
5822
8444
|
|
|
5823
8445
|
// src/webvr/wakelock-fallback.ts
|
|
5824
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==";
|
|
@@ -5952,7 +8574,7 @@ function releaseWebVRWakeLock() {
|
|
|
5952
8574
|
stopFallbackVideo();
|
|
5953
8575
|
}
|
|
5954
8576
|
function useWebVRWakeLock(enabled) {
|
|
5955
|
-
|
|
8577
|
+
useEffect18(() => {
|
|
5956
8578
|
if (!enabled) {
|
|
5957
8579
|
return;
|
|
5958
8580
|
}
|
|
@@ -6000,24 +8622,24 @@ var WebVR = forwardRef4(function WebVR2({
|
|
|
6000
8622
|
onDenied,
|
|
6001
8623
|
onUnknownDevice
|
|
6002
8624
|
}, ref) {
|
|
6003
|
-
const runtime =
|
|
6004
|
-
const controlsRef =
|
|
6005
|
-
const eventBus =
|
|
8625
|
+
const runtime = useContext19(WebVRRuntimeContext);
|
|
8626
|
+
const controlsRef = useContext19(PanoramaViewContext);
|
|
8627
|
+
const eventBus = useContext19(PanoEventBusContext);
|
|
6006
8628
|
const gl = useThree12((state) => state.gl);
|
|
6007
|
-
const gyroRef =
|
|
6008
|
-
const capabilitiesRef =
|
|
8629
|
+
const gyroRef = useRef18(null);
|
|
8630
|
+
const capabilitiesRef = useRef18({
|
|
6009
8631
|
mobile: false,
|
|
6010
8632
|
sensor: false,
|
|
6011
8633
|
webxr: false
|
|
6012
8634
|
});
|
|
6013
|
-
const availableRef =
|
|
6014
|
-
const modeRef =
|
|
6015
|
-
const webXRSessionRef =
|
|
8635
|
+
const availableRef = useRef18(false);
|
|
8636
|
+
const modeRef = useRef18(null);
|
|
8637
|
+
const webXRSessionRef = useRef18(null);
|
|
6016
8638
|
const [mode, setMode] = useState7(null);
|
|
6017
8639
|
const [settings, setSettings] = useState7(
|
|
6018
8640
|
() => initializeSettings(screensize, profile)
|
|
6019
8641
|
);
|
|
6020
|
-
const callbacksRef =
|
|
8642
|
+
const callbacksRef = useRef18({
|
|
6021
8643
|
onAvailable,
|
|
6022
8644
|
onDenied,
|
|
6023
8645
|
onEnterVR,
|
|
@@ -6226,7 +8848,7 @@ var WebVR = forwardRef4(function WebVR2({
|
|
|
6226
8848
|
}),
|
|
6227
8849
|
[enterVR, exitVR, requestPermission, toggleVR]
|
|
6228
8850
|
);
|
|
6229
|
-
|
|
8851
|
+
useEffect19(() => {
|
|
6230
8852
|
let active = true;
|
|
6231
8853
|
void detectWebVRCapabilities().then((capabilities) => {
|
|
6232
8854
|
if (!active) {
|
|
@@ -6248,7 +8870,7 @@ var WebVR = forwardRef4(function WebVR2({
|
|
|
6248
8870
|
active = false;
|
|
6249
8871
|
};
|
|
6250
8872
|
}, [desktopSupport, eventBus, fakeSupport, host, mobileVr]);
|
|
6251
|
-
|
|
8873
|
+
useEffect19(() => {
|
|
6252
8874
|
host.controller = controller;
|
|
6253
8875
|
return () => {
|
|
6254
8876
|
if (host.controller === controller) {
|
|
@@ -6257,10 +8879,10 @@ var WebVR = forwardRef4(function WebVR2({
|
|
|
6257
8879
|
}
|
|
6258
8880
|
};
|
|
6259
8881
|
}, [controller, host]);
|
|
6260
|
-
|
|
8882
|
+
useEffect19(() => {
|
|
6261
8883
|
updateWebVRHost(host, { chrome, mode, settings });
|
|
6262
8884
|
}, [chrome, host, mode, settings]);
|
|
6263
|
-
|
|
8885
|
+
useEffect19(() => {
|
|
6264
8886
|
if (mode !== "fake") {
|
|
6265
8887
|
return;
|
|
6266
8888
|
}
|
|
@@ -6284,7 +8906,7 @@ var WebVR = forwardRef4(function WebVR2({
|
|
|
6284
8906
|
document.removeEventListener("mousemove", onMouseMove);
|
|
6285
8907
|
};
|
|
6286
8908
|
}, [controlsRef, gl.domElement, mode, mousePointerLock]);
|
|
6287
|
-
|
|
8909
|
+
useEffect19(
|
|
6288
8910
|
() => () => {
|
|
6289
8911
|
const session2 = webXRSessionRef.current;
|
|
6290
8912
|
if (session2) {
|
|
@@ -6338,12 +8960,12 @@ var WebVR = forwardRef4(function WebVR2({
|
|
|
6338
8960
|
|
|
6339
8961
|
// src/sphere.tsx
|
|
6340
8962
|
import { useThree as useThree13 } from "@react-three/fiber";
|
|
6341
|
-
import { useEffect as
|
|
8963
|
+
import { useEffect as useEffect20, useMemo as useMemo12, useRef as useRef20, useState as useState8 } from "react";
|
|
6342
8964
|
import {
|
|
6343
8965
|
BackSide as BackSide2,
|
|
6344
8966
|
LinearFilter,
|
|
6345
8967
|
LinearMipmapLinearFilter,
|
|
6346
|
-
MathUtils as
|
|
8968
|
+
MathUtils as MathUtils5,
|
|
6347
8969
|
RepeatWrapping,
|
|
6348
8970
|
SRGBColorSpace,
|
|
6349
8971
|
TextureLoader
|
|
@@ -6371,7 +8993,7 @@ function resolveUrlAgainstFile(fileUrl, path) {
|
|
|
6371
8993
|
}
|
|
6372
8994
|
|
|
6373
8995
|
// src/pano-filter/pano-basic-material.tsx
|
|
6374
|
-
import { useLayoutEffect as useLayoutEffect2, useMemo as useMemo11, useRef as
|
|
8996
|
+
import { useLayoutEffect as useLayoutEffect2, useMemo as useMemo11, useRef as useRef19 } from "react";
|
|
6375
8997
|
|
|
6376
8998
|
// src/pano-filter/shaders.ts
|
|
6377
8999
|
var GLSL_FILTER_COMMON = `
|
|
@@ -6531,9 +9153,9 @@ function PanoBasicMaterial({
|
|
|
6531
9153
|
toneMapped = false
|
|
6532
9154
|
}) {
|
|
6533
9155
|
const snapshot = usePanoFilterSnapshot();
|
|
6534
|
-
const materialRef =
|
|
6535
|
-
const intensityRef =
|
|
6536
|
-
const intensityUniformRef =
|
|
9156
|
+
const materialRef = useRef19(null);
|
|
9157
|
+
const intensityRef = useRef19(snapshot.intensity);
|
|
9158
|
+
const intensityUniformRef = useRef19(null);
|
|
6537
9159
|
intensityRef.current = snapshot.intensity;
|
|
6538
9160
|
const active = isPanoFilterActive(snapshot);
|
|
6539
9161
|
const preset = snapshot.preset;
|
|
@@ -6588,11 +9210,11 @@ function PanoBasicMaterial({
|
|
|
6588
9210
|
import { jsx as jsx15, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
6589
9211
|
function useEquirectTexture(url, anisotropy, generateMipmaps, onLoad, onError) {
|
|
6590
9212
|
const [texture, setTexture] = useState8(null);
|
|
6591
|
-
const onLoadRef =
|
|
6592
|
-
const onErrorRef =
|
|
9213
|
+
const onLoadRef = useRef20(onLoad);
|
|
9214
|
+
const onErrorRef = useRef20(onError);
|
|
6593
9215
|
onLoadRef.current = onLoad;
|
|
6594
9216
|
onErrorRef.current = onError;
|
|
6595
|
-
|
|
9217
|
+
useEffect20(() => {
|
|
6596
9218
|
if (!url) {
|
|
6597
9219
|
setTexture(null);
|
|
6598
9220
|
return;
|
|
@@ -6631,7 +9253,7 @@ function useEquirectTexture(url, anisotropy, generateMipmaps, onLoad, onError) {
|
|
|
6631
9253
|
active = false;
|
|
6632
9254
|
};
|
|
6633
9255
|
}, [anisotropy, generateMipmaps, url]);
|
|
6634
|
-
|
|
9256
|
+
useEffect20(
|
|
6635
9257
|
() => () => {
|
|
6636
9258
|
texture?.dispose();
|
|
6637
9259
|
},
|
|
@@ -6670,11 +9292,11 @@ function Sphere({
|
|
|
6670
9292
|
onPreviewError
|
|
6671
9293
|
);
|
|
6672
9294
|
const displayTexture = texture ?? previewTexture;
|
|
6673
|
-
const readyRef =
|
|
6674
|
-
|
|
9295
|
+
const readyRef = useRef20(false);
|
|
9296
|
+
useEffect20(() => {
|
|
6675
9297
|
readyRef.current = false;
|
|
6676
9298
|
}, [resolvedPreviewUrl, src]);
|
|
6677
|
-
|
|
9299
|
+
useEffect20(() => {
|
|
6678
9300
|
if (!displayTexture || readyRef.current) {
|
|
6679
9301
|
return;
|
|
6680
9302
|
}
|
|
@@ -6687,7 +9309,7 @@ function Sphere({
|
|
|
6687
9309
|
return /* @__PURE__ */ jsxs9(
|
|
6688
9310
|
"mesh",
|
|
6689
9311
|
{
|
|
6690
|
-
rotation: [0,
|
|
9312
|
+
rotation: [0, MathUtils5.degToRad(90 + yawOffset), 0],
|
|
6691
9313
|
visible,
|
|
6692
9314
|
children: [
|
|
6693
9315
|
/* @__PURE__ */ jsx15("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
|
|
@@ -6708,18 +9330,18 @@ function Sphere({
|
|
|
6708
9330
|
import { useThree as useThree14 } from "@react-three/fiber";
|
|
6709
9331
|
import {
|
|
6710
9332
|
useCallback as useCallback9,
|
|
6711
|
-
useContext as
|
|
6712
|
-
useEffect as
|
|
9333
|
+
useContext as useContext20,
|
|
9334
|
+
useEffect as useEffect21,
|
|
6713
9335
|
useLayoutEffect as useLayoutEffect3,
|
|
6714
9336
|
useMemo as useMemo13,
|
|
6715
|
-
useRef as
|
|
9337
|
+
useRef as useRef21,
|
|
6716
9338
|
useState as useState9
|
|
6717
9339
|
} from "react";
|
|
6718
9340
|
import {
|
|
6719
9341
|
BackSide as BackSide3,
|
|
6720
9342
|
LinearFilter as LinearFilter2,
|
|
6721
9343
|
LinearMipmapLinearFilter as LinearMipmapLinearFilter2,
|
|
6722
|
-
MathUtils as
|
|
9344
|
+
MathUtils as MathUtils6,
|
|
6723
9345
|
RepeatWrapping as RepeatWrapping2,
|
|
6724
9346
|
SRGBColorSpace as SRGBColorSpace2,
|
|
6725
9347
|
TextureLoader as TextureLoader2,
|
|
@@ -6811,9 +9433,9 @@ function applyEquirectangularLayout(texture, anisotropy) {
|
|
|
6811
9433
|
function usePosterTexture(poster, onError) {
|
|
6812
9434
|
const gl = useThree14((state) => state.gl);
|
|
6813
9435
|
const [texture, setTexture] = useState9(null);
|
|
6814
|
-
const onErrorRef =
|
|
9436
|
+
const onErrorRef = useRef21(onError);
|
|
6815
9437
|
onErrorRef.current = onError;
|
|
6816
|
-
|
|
9438
|
+
useEffect21(() => {
|
|
6817
9439
|
let active = true;
|
|
6818
9440
|
setTexture(null);
|
|
6819
9441
|
if (!poster) {
|
|
@@ -6850,7 +9472,7 @@ function usePosterTexture(poster, onError) {
|
|
|
6850
9472
|
active = false;
|
|
6851
9473
|
};
|
|
6852
9474
|
}, [gl, poster]);
|
|
6853
|
-
|
|
9475
|
+
useEffect21(
|
|
6854
9476
|
() => () => {
|
|
6855
9477
|
texture?.dispose();
|
|
6856
9478
|
},
|
|
@@ -6908,8 +9530,8 @@ function PanoVideo({
|
|
|
6908
9530
|
onTrackChange
|
|
6909
9531
|
}) {
|
|
6910
9532
|
const gl = useThree14((state) => state.gl);
|
|
6911
|
-
const host =
|
|
6912
|
-
const overlay =
|
|
9533
|
+
const host = useContext20(PanoVideoHostContext);
|
|
9534
|
+
const overlay = useContext20(PanoChromeOverlayContext);
|
|
6913
9535
|
const variants = useMemo13(
|
|
6914
9536
|
() => resolvePanoVideoVariants({ poster, src, variants: variantsProp }),
|
|
6915
9537
|
[poster, src, variantsProp]
|
|
@@ -6929,17 +9551,17 @@ function PanoVideo({
|
|
|
6929
9551
|
() => captionsEnabled ? defaultPanoVideoTrackId(tracks) : null
|
|
6930
9552
|
);
|
|
6931
9553
|
const [ready, setReady] = useState9(false);
|
|
6932
|
-
const autoPlayRef =
|
|
9554
|
+
const autoPlayRef = useRef21(autoPlay);
|
|
6933
9555
|
autoPlayRef.current = autoPlay;
|
|
6934
|
-
const blockedRef =
|
|
6935
|
-
const captionAppearanceOverrideRef =
|
|
9556
|
+
const blockedRef = useRef21(false);
|
|
9557
|
+
const captionAppearanceOverrideRef = useRef21(
|
|
6936
9558
|
{}
|
|
6937
9559
|
);
|
|
6938
|
-
const mediaCapabilitiesRef =
|
|
9560
|
+
const mediaCapabilitiesRef = useRef21({
|
|
6939
9561
|
volumeAdjustable: true,
|
|
6940
9562
|
playbackRates: [...DEFAULT_PANO_VIDEO_PLAYBACK_RATES]
|
|
6941
9563
|
});
|
|
6942
|
-
const storeRef =
|
|
9564
|
+
const storeRef = useRef21(null);
|
|
6943
9565
|
if (!storeRef.current) {
|
|
6944
9566
|
storeRef.current = {
|
|
6945
9567
|
snapshot: {
|
|
@@ -6949,7 +9571,7 @@ function PanoVideo({
|
|
|
6949
9571
|
listeners: /* @__PURE__ */ new Set()
|
|
6950
9572
|
};
|
|
6951
9573
|
}
|
|
6952
|
-
const actionsRef =
|
|
9574
|
+
const actionsRef = useRef21({
|
|
6953
9575
|
play: async () => {
|
|
6954
9576
|
},
|
|
6955
9577
|
pause: () => {
|
|
@@ -6969,12 +9591,12 @@ function PanoVideo({
|
|
|
6969
9591
|
setCaptionAppearance: (_appearance) => {
|
|
6970
9592
|
}
|
|
6971
9593
|
});
|
|
6972
|
-
const onLoadRef =
|
|
6973
|
-
const onErrorRef =
|
|
6974
|
-
const onPlaybackStateChangeRef =
|
|
6975
|
-
const onEndedRef =
|
|
6976
|
-
const onVariantChangeRef =
|
|
6977
|
-
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);
|
|
6978
9600
|
onLoadRef.current = onLoad;
|
|
6979
9601
|
onErrorRef.current = onError;
|
|
6980
9602
|
onPlaybackStateChangeRef.current = onPlaybackStateChange;
|
|
@@ -6998,7 +9620,7 @@ function PanoVideo({
|
|
|
6998
9620
|
texture.generateMipmaps = false;
|
|
6999
9621
|
return { video, texture };
|
|
7000
9622
|
}, []);
|
|
7001
|
-
|
|
9623
|
+
useEffect21(
|
|
7002
9624
|
() => () => {
|
|
7003
9625
|
if (!resource) {
|
|
7004
9626
|
return;
|
|
@@ -7013,13 +9635,13 @@ function PanoVideo({
|
|
|
7013
9635
|
},
|
|
7014
9636
|
[resource]
|
|
7015
9637
|
);
|
|
7016
|
-
|
|
9638
|
+
useEffect21(() => {
|
|
7017
9639
|
if (!resource) {
|
|
7018
9640
|
return;
|
|
7019
9641
|
}
|
|
7020
9642
|
resource.texture.anisotropy = gl.capabilities.getMaxAnisotropy();
|
|
7021
9643
|
}, [gl, resource]);
|
|
7022
|
-
|
|
9644
|
+
useEffect21(() => {
|
|
7023
9645
|
if (!resource || !overlay?.overlayElement) {
|
|
7024
9646
|
return;
|
|
7025
9647
|
}
|
|
@@ -7172,10 +9794,10 @@ function PanoVideo({
|
|
|
7172
9794
|
};
|
|
7173
9795
|
emitSnapshot();
|
|
7174
9796
|
}, [emitSnapshot, playbackRates, resource]);
|
|
7175
|
-
|
|
9797
|
+
useEffect21(() => {
|
|
7176
9798
|
emitSnapshot();
|
|
7177
9799
|
}, [emitSnapshot]);
|
|
7178
|
-
|
|
9800
|
+
useEffect21(() => {
|
|
7179
9801
|
if (!resource || !activeVariant || !mediaKey) {
|
|
7180
9802
|
return;
|
|
7181
9803
|
}
|
|
@@ -7232,7 +9854,7 @@ function PanoVideo({
|
|
|
7232
9854
|
video.removeEventListener("error", handleError);
|
|
7233
9855
|
};
|
|
7234
9856
|
}, [mediaKey, resource]);
|
|
7235
|
-
|
|
9857
|
+
useEffect21(() => {
|
|
7236
9858
|
if (!resource) {
|
|
7237
9859
|
return;
|
|
7238
9860
|
}
|
|
@@ -7322,7 +9944,7 @@ function PanoVideo({
|
|
|
7322
9944
|
}
|
|
7323
9945
|
};
|
|
7324
9946
|
}, [emitSnapshot, resource]);
|
|
7325
|
-
|
|
9947
|
+
useEffect21(() => {
|
|
7326
9948
|
if (!resource) {
|
|
7327
9949
|
return;
|
|
7328
9950
|
}
|
|
@@ -7335,7 +9957,7 @@ function PanoVideo({
|
|
|
7335
9957
|
video.playsInline = playsInline;
|
|
7336
9958
|
video.preload = preload;
|
|
7337
9959
|
}, [loop, muted, playsInline, preload, resource, volume]);
|
|
7338
|
-
|
|
9960
|
+
useEffect21(() => {
|
|
7339
9961
|
if (!resource) {
|
|
7340
9962
|
return;
|
|
7341
9963
|
}
|
|
@@ -7385,7 +10007,7 @@ function PanoVideo({
|
|
|
7385
10007
|
video.removeEventListener("ratechange", handleVolume);
|
|
7386
10008
|
};
|
|
7387
10009
|
}, [emitSnapshot, resource]);
|
|
7388
|
-
|
|
10010
|
+
useEffect21(() => {
|
|
7389
10011
|
if (!resource) {
|
|
7390
10012
|
return;
|
|
7391
10013
|
}
|
|
@@ -7420,7 +10042,7 @@ function PanoVideo({
|
|
|
7420
10042
|
video.textTracks.removeEventListener("change", applyModes);
|
|
7421
10043
|
};
|
|
7422
10044
|
}, [emitSnapshot, resource, trackId, tracks]);
|
|
7423
|
-
|
|
10045
|
+
useEffect21(() => {
|
|
7424
10046
|
if (!captionsEnabled) {
|
|
7425
10047
|
setTrackId(null);
|
|
7426
10048
|
return;
|
|
@@ -7435,7 +10057,7 @@ function PanoVideo({
|
|
|
7435
10057
|
activeTexture ? /* @__PURE__ */ jsxs10(
|
|
7436
10058
|
"mesh",
|
|
7437
10059
|
{
|
|
7438
|
-
rotation: [0,
|
|
10060
|
+
rotation: [0, MathUtils6.degToRad(90 + yawOffset), 0],
|
|
7439
10061
|
visible,
|
|
7440
10062
|
children: [
|
|
7441
10063
|
/* @__PURE__ */ jsx16("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
|
|
@@ -7459,10 +10081,10 @@ import { useFrame as useFrame12, useThree as useThree19 } from "@react-three/fib
|
|
|
7459
10081
|
import {
|
|
7460
10082
|
Fragment as Fragment6,
|
|
7461
10083
|
useCallback as useCallback10,
|
|
7462
|
-
useContext as
|
|
7463
|
-
useEffect as
|
|
10084
|
+
useContext as useContext22,
|
|
10085
|
+
useEffect as useEffect26,
|
|
7464
10086
|
useMemo as useMemo18,
|
|
7465
|
-
useRef as
|
|
10087
|
+
useRef as useRef25,
|
|
7466
10088
|
useState as useState11
|
|
7467
10089
|
} from "react";
|
|
7468
10090
|
import {
|
|
@@ -7519,7 +10141,7 @@ function isSnapshotTransition(preset) {
|
|
|
7519
10141
|
|
|
7520
10142
|
// src/scene-transitions/particle-overlay.tsx
|
|
7521
10143
|
import { useFrame as useFrame9, useThree as useThree15 } from "@react-three/fiber";
|
|
7522
|
-
import { useEffect as
|
|
10144
|
+
import { useEffect as useEffect22, useMemo as useMemo14, useRef as useRef22 } from "react";
|
|
7523
10145
|
import {
|
|
7524
10146
|
DoubleSide as DoubleSide2,
|
|
7525
10147
|
InstancedBufferAttribute,
|
|
@@ -7527,7 +10149,7 @@ import {
|
|
|
7527
10149
|
PlaneGeometry as PlaneGeometry3,
|
|
7528
10150
|
ShaderMaterial as ShaderMaterial2,
|
|
7529
10151
|
Vector2 as Vector24,
|
|
7530
|
-
Vector3 as
|
|
10152
|
+
Vector3 as Vector39
|
|
7531
10153
|
} from "three";
|
|
7532
10154
|
|
|
7533
10155
|
// src/scene-transitions/glsl.ts
|
|
@@ -7659,10 +10281,10 @@ function ParticleOverlay({
|
|
|
7659
10281
|
onFinish
|
|
7660
10282
|
}) {
|
|
7661
10283
|
const { camera } = useThree15();
|
|
7662
|
-
const meshRef =
|
|
7663
|
-
const startRef =
|
|
7664
|
-
const finishedRef =
|
|
7665
|
-
const directionRef =
|
|
10284
|
+
const meshRef = useRef22(null);
|
|
10285
|
+
const startRef = useRef22(null);
|
|
10286
|
+
const finishedRef = useRef22(false);
|
|
10287
|
+
const directionRef = useRef22(new Vector39());
|
|
7666
10288
|
const geometry = useMemo14(() => createParticleGeometry(), []);
|
|
7667
10289
|
const material = useMemo14(
|
|
7668
10290
|
() => new ShaderMaterial2({
|
|
@@ -7680,9 +10302,9 @@ function ParticleOverlay({
|
|
|
7680
10302
|
}),
|
|
7681
10303
|
[snapshot.texture]
|
|
7682
10304
|
);
|
|
7683
|
-
|
|
7684
|
-
|
|
7685
|
-
|
|
10305
|
+
useEffect22(() => () => geometry.dispose(), [geometry]);
|
|
10306
|
+
useEffect22(() => () => material.dispose(), [material]);
|
|
10307
|
+
useEffect22(() => {
|
|
7686
10308
|
startRef.current = null;
|
|
7687
10309
|
finishedRef.current = false;
|
|
7688
10310
|
material.uniforms.progress.value = 0;
|
|
@@ -7718,8 +10340,8 @@ function ParticleOverlay({
|
|
|
7718
10340
|
|
|
7719
10341
|
// src/scene-transitions/snapshot-overlay.tsx
|
|
7720
10342
|
import { useFrame as useFrame10, useThree as useThree16 } from "@react-three/fiber";
|
|
7721
|
-
import { useEffect as
|
|
7722
|
-
import { Vector3 as
|
|
10343
|
+
import { useEffect as useEffect23, useMemo as useMemo15, useRef as useRef23 } from "react";
|
|
10344
|
+
import { Vector3 as Vector310 } from "three";
|
|
7723
10345
|
|
|
7724
10346
|
// src/scene-transitions/snapshot-shaders.ts
|
|
7725
10347
|
import { DoubleSide as DoubleSide3, ShaderMaterial as ShaderMaterial3, Vector2 as Vector25 } from "three";
|
|
@@ -8007,18 +10629,18 @@ function SnapshotOverlay({
|
|
|
8007
10629
|
onFinish
|
|
8008
10630
|
}) {
|
|
8009
10631
|
const { camera, gl } = useThree16();
|
|
8010
|
-
const meshRef =
|
|
8011
|
-
const startRef =
|
|
8012
|
-
const finishedRef =
|
|
8013
|
-
const directionRef =
|
|
10632
|
+
const meshRef = useRef23(null);
|
|
10633
|
+
const startRef = useRef23(null);
|
|
10634
|
+
const finishedRef = useRef23(false);
|
|
10635
|
+
const directionRef = useRef23(new Vector310());
|
|
8014
10636
|
const material = useMemo15(() => {
|
|
8015
10637
|
if (!isSnapshotTransition(transition.preset)) {
|
|
8016
10638
|
return null;
|
|
8017
10639
|
}
|
|
8018
10640
|
return createSnapshotMaterial(transition.preset, snapshot.texture);
|
|
8019
10641
|
}, [snapshot.texture, transition.preset]);
|
|
8020
|
-
|
|
8021
|
-
|
|
10642
|
+
useEffect23(() => () => material?.dispose(), [material]);
|
|
10643
|
+
useEffect23(() => {
|
|
8022
10644
|
startRef.current = null;
|
|
8023
10645
|
finishedRef.current = false;
|
|
8024
10646
|
if (material) {
|
|
@@ -8102,8 +10724,8 @@ function TransitionOverlay(props) {
|
|
|
8102
10724
|
import { useThree as useThree17 } from "@react-three/fiber";
|
|
8103
10725
|
import {
|
|
8104
10726
|
createContext as createContext11,
|
|
8105
|
-
useContext as
|
|
8106
|
-
useEffect as
|
|
10727
|
+
useContext as useContext21,
|
|
10728
|
+
useEffect as useEffect24,
|
|
8107
10729
|
useMemo as useMemo16
|
|
8108
10730
|
} from "react";
|
|
8109
10731
|
|
|
@@ -8354,23 +10976,23 @@ function TileTextureManagerProvider({
|
|
|
8354
10976
|
}),
|
|
8355
10977
|
[anisotropy, maxConcurrentLoads, maxTextureMemoryMb]
|
|
8356
10978
|
);
|
|
8357
|
-
|
|
10979
|
+
useEffect24(() => {
|
|
8358
10980
|
manager.resume();
|
|
8359
10981
|
return () => manager.dispose();
|
|
8360
10982
|
}, [manager]);
|
|
8361
10983
|
return /* @__PURE__ */ jsx20(TileTextureManagerContext.Provider, { value: manager, children });
|
|
8362
10984
|
}
|
|
8363
10985
|
function useSharedTileTextureManager() {
|
|
8364
|
-
return
|
|
10986
|
+
return useContext21(TileTextureManagerContext);
|
|
8365
10987
|
}
|
|
8366
10988
|
|
|
8367
10989
|
// src/tile/tile.tsx
|
|
8368
10990
|
import { useFrame as useFrame11, useThree as useThree18 } from "@react-three/fiber";
|
|
8369
10991
|
import {
|
|
8370
10992
|
memo,
|
|
8371
|
-
useEffect as
|
|
10993
|
+
useEffect as useEffect25,
|
|
8372
10994
|
useMemo as useMemo17,
|
|
8373
|
-
useRef as
|
|
10995
|
+
useRef as useRef24,
|
|
8374
10996
|
useState as useState10
|
|
8375
10997
|
} from "react";
|
|
8376
10998
|
import {
|
|
@@ -8382,7 +11004,7 @@ import {
|
|
|
8382
11004
|
PerspectiveCamera as PerspectiveCamera4,
|
|
8383
11005
|
SRGBColorSpace as SRGBColorSpace4,
|
|
8384
11006
|
TextureLoader as TextureLoader4,
|
|
8385
|
-
Vector3 as
|
|
11007
|
+
Vector3 as Vector312
|
|
8386
11008
|
} from "three";
|
|
8387
11009
|
|
|
8388
11010
|
// src/tile/face-layout.ts
|
|
@@ -8390,7 +11012,7 @@ import {
|
|
|
8390
11012
|
Box3,
|
|
8391
11013
|
Euler as Euler3,
|
|
8392
11014
|
Quaternion as Quaternion2,
|
|
8393
|
-
Vector3 as
|
|
11015
|
+
Vector3 as Vector311
|
|
8394
11016
|
} from "three";
|
|
8395
11017
|
var CUBE_FACES = ["f", "r", "b", "l", "u", "d"];
|
|
8396
11018
|
var PREVIEW_FACE_ORDER = ["l", "f", "r", "b", "u", "d"];
|
|
@@ -8454,12 +11076,12 @@ function getTileBoundingBox(address, radius = CUBE_RADIUS) {
|
|
|
8454
11076
|
const halfWidth = local.width / 2;
|
|
8455
11077
|
const halfHeight = local.height / 2;
|
|
8456
11078
|
const quaternion = getFaceQuaternion(address.face);
|
|
8457
|
-
const position = new
|
|
11079
|
+
const position = new Vector311(...transform.position);
|
|
8458
11080
|
const corners = [
|
|
8459
|
-
new
|
|
8460
|
-
new
|
|
8461
|
-
new
|
|
8462
|
-
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)
|
|
8463
11085
|
];
|
|
8464
11086
|
for (const corner of corners) {
|
|
8465
11087
|
corner.applyQuaternion(quaternion).add(position);
|
|
@@ -8577,9 +11199,9 @@ var PREVIEW_RADIUS = CUBE_RADIUS + 0.05;
|
|
|
8577
11199
|
var SHARED_TILE_GEOMETRY = new PlaneGeometry4(1, 1);
|
|
8578
11200
|
function usePreviewTexture(url, anisotropy, onError) {
|
|
8579
11201
|
const [texture, setTexture] = useState10(null);
|
|
8580
|
-
const onErrorRef =
|
|
11202
|
+
const onErrorRef = useRef24(onError);
|
|
8581
11203
|
onErrorRef.current = onError;
|
|
8582
|
-
|
|
11204
|
+
useEffect25(() => {
|
|
8583
11205
|
if (!url) {
|
|
8584
11206
|
setTexture(null);
|
|
8585
11207
|
return;
|
|
@@ -8616,7 +11238,7 @@ function usePreviewTexture(url, anisotropy, onError) {
|
|
|
8616
11238
|
active = false;
|
|
8617
11239
|
};
|
|
8618
11240
|
}, [anisotropy, url]);
|
|
8619
|
-
|
|
11241
|
+
useEffect25(
|
|
8620
11242
|
() => () => {
|
|
8621
11243
|
texture?.dispose();
|
|
8622
11244
|
},
|
|
@@ -8647,7 +11269,7 @@ function PreviewFace({
|
|
|
8647
11269
|
uv.needsUpdate = true;
|
|
8648
11270
|
return nextGeometry;
|
|
8649
11271
|
}, [face, faceOrder]);
|
|
8650
|
-
|
|
11272
|
+
useEffect25(
|
|
8651
11273
|
() => () => {
|
|
8652
11274
|
geometry.dispose();
|
|
8653
11275
|
},
|
|
@@ -8695,7 +11317,7 @@ function useManagedTexture(manager, key, url, address) {
|
|
|
8695
11317
|
snapshot: manager.getSnapshot(key)
|
|
8696
11318
|
}));
|
|
8697
11319
|
const snapshot = managedState.manager === manager && managedState.key === key && managedState.url === url ? managedState.snapshot : manager.getSnapshot(key);
|
|
8698
|
-
|
|
11320
|
+
useEffect25(
|
|
8699
11321
|
() => manager.acquire(key, url, address, (nextSnapshot) => {
|
|
8700
11322
|
setManagedState({
|
|
8701
11323
|
manager,
|
|
@@ -8846,8 +11468,8 @@ function parentAddresses(child, parentLevel, parentFaceSize, tileSize) {
|
|
|
8846
11468
|
return addresses;
|
|
8847
11469
|
}
|
|
8848
11470
|
function centerFacingAddress(candidates, camera) {
|
|
8849
|
-
const direction = camera.getWorldDirection(new
|
|
8850
|
-
const center = new
|
|
11471
|
+
const direction = camera.getWorldDirection(new Vector312());
|
|
11472
|
+
const center = new Vector312();
|
|
8851
11473
|
let bestCandidate = candidates[0];
|
|
8852
11474
|
let bestAlignment = -Infinity;
|
|
8853
11475
|
for (const candidate of candidates) {
|
|
@@ -8930,9 +11552,9 @@ function Tile({
|
|
|
8930
11552
|
onPreviewError
|
|
8931
11553
|
);
|
|
8932
11554
|
const sharedManager = useSharedTileTextureManager();
|
|
8933
|
-
const progressRef =
|
|
8934
|
-
const errorRef =
|
|
8935
|
-
const levelChangeRef =
|
|
11555
|
+
const progressRef = useRef24(onLoadProgress);
|
|
11556
|
+
const errorRef = useRef24(onTileError);
|
|
11557
|
+
const levelChangeRef = useRef24(onLevelChange);
|
|
8936
11558
|
progressRef.current = onLoadProgress;
|
|
8937
11559
|
errorRef.current = onTileError;
|
|
8938
11560
|
levelChangeRef.current = onLevelChange;
|
|
@@ -8957,7 +11579,7 @@ function Tile({
|
|
|
8957
11579
|
]
|
|
8958
11580
|
);
|
|
8959
11581
|
const manager = sharedManager ?? ownedManager;
|
|
8960
|
-
|
|
11582
|
+
useEffect25(() => {
|
|
8961
11583
|
manager.resume();
|
|
8962
11584
|
return () => {
|
|
8963
11585
|
if (manager === ownedManager) {
|
|
@@ -8967,11 +11589,11 @@ function Tile({
|
|
|
8967
11589
|
queueMicrotask(() => manager.releaseUnused());
|
|
8968
11590
|
};
|
|
8969
11591
|
}, [manager, ownedManager]);
|
|
8970
|
-
const readyRef =
|
|
8971
|
-
|
|
11592
|
+
const readyRef = useRef24(false);
|
|
11593
|
+
useEffect25(() => {
|
|
8972
11594
|
readyRef.current = false;
|
|
8973
11595
|
}, [effectivePreviewUrl]);
|
|
8974
|
-
|
|
11596
|
+
useEffect25(() => {
|
|
8975
11597
|
if (!previewTexture || readyRef.current) {
|
|
8976
11598
|
return;
|
|
8977
11599
|
}
|
|
@@ -8987,23 +11609,23 @@ function Tile({
|
|
|
8987
11609
|
[baseUrl, resolveTileUrl, template]
|
|
8988
11610
|
);
|
|
8989
11611
|
const [layers, setLayers] = useState10([]);
|
|
8990
|
-
const layerTokenRef =
|
|
8991
|
-
const currentLevelRef =
|
|
8992
|
-
const lastUpdateAtRef =
|
|
8993
|
-
const visibilityDirtyRef =
|
|
8994
|
-
const lastVisibilityQuaternionRef =
|
|
8995
|
-
const lastVisibilityFovRef =
|
|
8996
|
-
const lastViewportRef =
|
|
8997
|
-
const frustumRef =
|
|
8998
|
-
const projectionMatrixRef =
|
|
8999
|
-
const visibilityCameraRef =
|
|
9000
|
-
|
|
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(() => {
|
|
9001
11623
|
currentLevelRef.current = 1;
|
|
9002
11624
|
layerTokenRef.current = "";
|
|
9003
11625
|
visibilityDirtyRef.current = true;
|
|
9004
11626
|
setLayers([]);
|
|
9005
11627
|
}, [manager, multiresToken]);
|
|
9006
|
-
|
|
11628
|
+
useEffect25(() => {
|
|
9007
11629
|
if (loadMode !== "preview") {
|
|
9008
11630
|
return;
|
|
9009
11631
|
}
|
|
@@ -9154,9 +11776,9 @@ function SnapshotCapture({
|
|
|
9154
11776
|
onCaptured
|
|
9155
11777
|
}) {
|
|
9156
11778
|
const { camera, gl, scene, size } = useThree19();
|
|
9157
|
-
const capturedRequestRef =
|
|
9158
|
-
const renderTargetRef =
|
|
9159
|
-
|
|
11779
|
+
const capturedRequestRef = useRef25(0);
|
|
11780
|
+
const renderTargetRef = useRef25(null);
|
|
11781
|
+
useEffect26(
|
|
9160
11782
|
() => () => {
|
|
9161
11783
|
renderTargetRef.current?.dispose();
|
|
9162
11784
|
renderTargetRef.current = null;
|
|
@@ -9211,7 +11833,7 @@ function ScenesController({
|
|
|
9211
11833
|
onTransitionError,
|
|
9212
11834
|
snapshotMaxPixels = 3686400
|
|
9213
11835
|
}) {
|
|
9214
|
-
const controlsRef =
|
|
11836
|
+
const controlsRef = useContext22(PanoramaViewContext);
|
|
9215
11837
|
const manager = useSharedTileTextureManager();
|
|
9216
11838
|
const transition = useMemo18(
|
|
9217
11839
|
() => resolveTransition(transitionInput),
|
|
@@ -9234,13 +11856,13 @@ function ScenesController({
|
|
|
9234
11856
|
const [transitionRunId, setTransitionRunId] = useState11(0);
|
|
9235
11857
|
const [snapshot, setSnapshot] = useState11(null);
|
|
9236
11858
|
const [recoveryKey, setRecoveryKey] = useState11(0);
|
|
9237
|
-
const requestedSceneIdRef =
|
|
9238
|
-
const captureReasonRef =
|
|
9239
|
-
const interactionReleaseRef =
|
|
9240
|
-
const slotsRef =
|
|
9241
|
-
const phaseRef =
|
|
9242
|
-
const liveSlotRef =
|
|
9243
|
-
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);
|
|
9244
11866
|
slotsRef.current = slots;
|
|
9245
11867
|
phaseRef.current = phase;
|
|
9246
11868
|
liveSlotRef.current = liveSlot;
|
|
@@ -9262,7 +11884,7 @@ function ScenesController({
|
|
|
9262
11884
|
setPendingSlot(nextSlot);
|
|
9263
11885
|
setPhase("preloading");
|
|
9264
11886
|
}, []);
|
|
9265
|
-
|
|
11887
|
+
useEffect26(() => {
|
|
9266
11888
|
const requested = sceneMap.get(activeSceneId);
|
|
9267
11889
|
if (!requested) {
|
|
9268
11890
|
reportError(activeSceneId, new Error(`Unknown panorama scene: ${activeSceneId}`));
|
|
@@ -9364,12 +11986,12 @@ function ScenesController({
|
|
|
9364
11986
|
});
|
|
9365
11987
|
}
|
|
9366
11988
|
}, [onTransitionEnd, pendingSlot, releaseInteraction, snapshot, transition.preset]);
|
|
9367
|
-
|
|
11989
|
+
useEffect26(() => () => {
|
|
9368
11990
|
releaseInteraction();
|
|
9369
11991
|
snapshot?.dispose();
|
|
9370
11992
|
}, [releaseInteraction, snapshot]);
|
|
9371
11993
|
const { gl } = useThree19();
|
|
9372
|
-
|
|
11994
|
+
useEffect26(() => {
|
|
9373
11995
|
const canvas = gl.domElement;
|
|
9374
11996
|
const onContextLost = (event) => {
|
|
9375
11997
|
event.preventDefault();
|
|
@@ -9452,7 +12074,7 @@ function Scenes({
|
|
|
9452
12074
|
|
|
9453
12075
|
// src/hotspot/image-hotspot.tsx
|
|
9454
12076
|
import { useThree as useThree21 } from "@react-three/fiber";
|
|
9455
|
-
import { useEffect as
|
|
12077
|
+
import { useEffect as useEffect29, useRef as useRef27, useState as useState14 } from "react";
|
|
9456
12078
|
import {
|
|
9457
12079
|
ClampToEdgeWrapping as ClampToEdgeWrapping3,
|
|
9458
12080
|
LinearFilter as LinearFilter6,
|
|
@@ -9464,35 +12086,35 @@ import {
|
|
|
9464
12086
|
// src/hotspot/hotspot-anchor.tsx
|
|
9465
12087
|
import { useFrame as useFrame13, useThree as useThree20 } from "@react-three/fiber";
|
|
9466
12088
|
import {
|
|
9467
|
-
useContext as
|
|
9468
|
-
useEffect as
|
|
12089
|
+
useContext as useContext24,
|
|
12090
|
+
useEffect as useEffect28,
|
|
9469
12091
|
useLayoutEffect as useLayoutEffect4,
|
|
9470
12092
|
useMemo as useMemo20,
|
|
9471
|
-
useRef as
|
|
12093
|
+
useRef as useRef26,
|
|
9472
12094
|
useState as useState13
|
|
9473
12095
|
} from "react";
|
|
9474
12096
|
import {
|
|
9475
12097
|
Box3 as Box33,
|
|
9476
12098
|
EdgesGeometry,
|
|
9477
|
-
MathUtils as
|
|
12099
|
+
MathUtils as MathUtils7,
|
|
9478
12100
|
Matrix4 as Matrix42,
|
|
9479
12101
|
Plane,
|
|
9480
12102
|
PlaneGeometry as PlaneGeometry5,
|
|
9481
12103
|
PerspectiveCamera as PerspectiveCamera5,
|
|
9482
12104
|
Quaternion as Quaternion3,
|
|
9483
12105
|
Ray,
|
|
9484
|
-
Vector3 as
|
|
12106
|
+
Vector3 as Vector313
|
|
9485
12107
|
} from "three";
|
|
9486
12108
|
|
|
9487
12109
|
// src/hotspot/hotspot-tooltip.tsx
|
|
9488
|
-
import { useEffect as
|
|
12110
|
+
import { useEffect as useEffect27, useMemo as useMemo19, useState as useState12 } from "react";
|
|
9489
12111
|
|
|
9490
12112
|
// src/webvr/stereo-html.tsx
|
|
9491
12113
|
import { Html } from "@react-three/drei";
|
|
9492
|
-
import { useContext as
|
|
12114
|
+
import { useContext as useContext23, useSyncExternalStore as useSyncExternalStore6 } from "react";
|
|
9493
12115
|
import { Fragment as Fragment7, jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
9494
12116
|
function useFallbackStereoView() {
|
|
9495
|
-
const runtime =
|
|
12117
|
+
const runtime = useContext23(WebVRRuntimeContext);
|
|
9496
12118
|
const host = runtime?.host ?? null;
|
|
9497
12119
|
const fallback = useSyncExternalStore6(
|
|
9498
12120
|
(onStoreChange) => host ? subscribeWebVRHost(host, onStoreChange) : () => void 0,
|
|
@@ -9609,7 +12231,7 @@ function HotspotTooltip({
|
|
|
9609
12231
|
appearance
|
|
9610
12232
|
}) {
|
|
9611
12233
|
const [imageFailed, setImageFailed] = useState12(false);
|
|
9612
|
-
|
|
12234
|
+
useEffect27(() => {
|
|
9613
12235
|
setImageFailed(false);
|
|
9614
12236
|
}, [content.image]);
|
|
9615
12237
|
const showImage = Boolean(content.image) && !imageFailed;
|
|
@@ -9667,28 +12289,28 @@ var DEFAULT_REFERENCE_FOV = 75;
|
|
|
9667
12289
|
var MIN_ANGULAR_SIZE = 0.01;
|
|
9668
12290
|
var MAX_ANGULAR_SIZE = 179;
|
|
9669
12291
|
var DRAG_EPSILON_DEGREES = 1e-3;
|
|
9670
|
-
var LOCAL_FORWARD = new
|
|
12292
|
+
var LOCAL_FORWARD = new Vector313(0, 0, 1);
|
|
9671
12293
|
var TOOLTIP_WORLD_BOX = new Box33();
|
|
9672
12294
|
var TOOLTIP_LOCAL_BOX = new Box33();
|
|
9673
|
-
var TOOLTIP_CORNER = new
|
|
12295
|
+
var TOOLTIP_CORNER = new Vector313();
|
|
9674
12296
|
var TOOLTIP_INVERSE = new Matrix42();
|
|
9675
|
-
var TOOLTIP_WORLD_CORNER = new
|
|
9676
|
-
var TOOLTIP_PROJECTED = new
|
|
9677
|
-
var TOOLTIP_RAY_ORIGIN = new
|
|
9678
|
-
var TOOLTIP_RAY_FAR = new
|
|
9679
|
-
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();
|
|
9680
12302
|
var TOOLTIP_RAY = new Ray();
|
|
9681
12303
|
var TOOLTIP_PLANE = new Plane();
|
|
9682
|
-
var TOOLTIP_INTERSECTION = new
|
|
9683
|
-
var TOOLTIP_PLANE_NORMAL = new
|
|
9684
|
-
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();
|
|
9685
12307
|
var HOTSPOT_MODE_RENDERING = {
|
|
9686
12308
|
surface: { orientation: "surface", placement: "surface" },
|
|
9687
12309
|
billboard: { orientation: "billboard", placement: "floating" }
|
|
9688
12310
|
};
|
|
9689
12311
|
function angularSizeToWorldSize(size, radius) {
|
|
9690
|
-
const safeSize = Number.isFinite(size) ?
|
|
9691
|
-
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);
|
|
9692
12314
|
}
|
|
9693
12315
|
function resolveScale(scale) {
|
|
9694
12316
|
return Number.isFinite(scale) && scale > 0 ? scale : 1;
|
|
@@ -9701,7 +12323,7 @@ function resolveDistance(placement, distance, width, height) {
|
|
|
9701
12323
|
if (!Number.isFinite(distance)) {
|
|
9702
12324
|
return DEFAULT_FLOATING_DISTANCE;
|
|
9703
12325
|
}
|
|
9704
|
-
return
|
|
12326
|
+
return MathUtils7.clamp(Math.abs(distance), 0.1, maximumDistance);
|
|
9705
12327
|
}
|
|
9706
12328
|
function applyHotspotTransform(group, camera, orientation2, surfaceQuaternion3, rotation, scaleMode, referenceFov, useAngularScale, worldWidth, worldHeight) {
|
|
9707
12329
|
if (orientation2 === "billboard") {
|
|
@@ -9709,7 +12331,7 @@ function applyHotspotTransform(group, camera, orientation2, surfaceQuaternion3,
|
|
|
9709
12331
|
} else {
|
|
9710
12332
|
group.quaternion.copy(surfaceQuaternion3);
|
|
9711
12333
|
}
|
|
9712
|
-
group.rotateOnAxis(LOCAL_FORWARD,
|
|
12334
|
+
group.rotateOnAxis(LOCAL_FORWARD, MathUtils7.degToRad(-rotation));
|
|
9713
12335
|
const scaleFactor = scaleMode === "fixed" && camera instanceof PerspectiveCamera5 ? fixedScaleFactor(camera.fov, referenceFov) : 1;
|
|
9714
12336
|
group.scale.set(
|
|
9715
12337
|
(useAngularScale ? worldWidth : 1) * scaleFactor,
|
|
@@ -9719,33 +12341,33 @@ function applyHotspotTransform(group, camera, orientation2, surfaceQuaternion3,
|
|
|
9719
12341
|
group.updateMatrixWorld();
|
|
9720
12342
|
}
|
|
9721
12343
|
function maximumHotspotDistance(width, height) {
|
|
9722
|
-
const safeWidth =
|
|
12344
|
+
const safeWidth = MathUtils7.clamp(
|
|
9723
12345
|
Math.abs(Number.isFinite(width) ? width : MIN_ANGULAR_SIZE),
|
|
9724
12346
|
MIN_ANGULAR_SIZE,
|
|
9725
12347
|
MAX_ANGULAR_SIZE
|
|
9726
12348
|
);
|
|
9727
|
-
const safeHeight =
|
|
12349
|
+
const safeHeight = MathUtils7.clamp(
|
|
9728
12350
|
Math.abs(Number.isFinite(height) ? height : MIN_ANGULAR_SIZE),
|
|
9729
12351
|
MIN_ANGULAR_SIZE,
|
|
9730
12352
|
MAX_ANGULAR_SIZE
|
|
9731
12353
|
);
|
|
9732
12354
|
const cornerFactor = Math.hypot(
|
|
9733
12355
|
1,
|
|
9734
|
-
Math.tan(
|
|
9735
|
-
Math.tan(
|
|
12356
|
+
Math.tan(MathUtils7.degToRad(safeWidth) / 2),
|
|
12357
|
+
Math.tan(MathUtils7.degToRad(safeHeight) / 2)
|
|
9736
12358
|
);
|
|
9737
12359
|
return (PANORAMA_RADIUS - PANORAMA_SURFACE_INSET) / cornerFactor;
|
|
9738
12360
|
}
|
|
9739
12361
|
function fixedScaleFactor(cameraFov, referenceFov) {
|
|
9740
|
-
const safeReferenceFov =
|
|
9741
|
-
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);
|
|
9742
12364
|
}
|
|
9743
12365
|
function createSurfaceQuaternion(position) {
|
|
9744
12366
|
const outward = panoPositionToVector3(position).normalize();
|
|
9745
12367
|
const inward = outward.clone().negate();
|
|
9746
|
-
const pitch =
|
|
9747
|
-
const yaw =
|
|
9748
|
-
const localUp = new
|
|
12368
|
+
const pitch = MathUtils7.degToRad(position.pitch);
|
|
12369
|
+
const yaw = MathUtils7.degToRad(position.yaw);
|
|
12370
|
+
const localUp = new Vector313(
|
|
9749
12371
|
-Math.sin(pitch) * Math.sin(yaw),
|
|
9750
12372
|
Math.cos(pitch),
|
|
9751
12373
|
Math.sin(pitch) * Math.cos(yaw)
|
|
@@ -9765,7 +12387,7 @@ function makeInteractionEvent(id, position, event) {
|
|
|
9765
12387
|
function angularDistance(a, b) {
|
|
9766
12388
|
const aVector = panoPositionToVector3(a);
|
|
9767
12389
|
const bVector = panoPositionToVector3(b);
|
|
9768
|
-
return
|
|
12390
|
+
return MathUtils7.radToDeg(aVector.angleTo(bVector));
|
|
9769
12391
|
}
|
|
9770
12392
|
function isTooltipOpen(trigger, hovered, focused, pinned) {
|
|
9771
12393
|
switch (trigger) {
|
|
@@ -9996,14 +12618,14 @@ function HotspotAnchor({
|
|
|
9996
12618
|
onPositionChange,
|
|
9997
12619
|
onDragEnd
|
|
9998
12620
|
}) {
|
|
9999
|
-
const controlsRef =
|
|
10000
|
-
const eventBus =
|
|
12621
|
+
const controlsRef = useContext24(PanoramaViewContext);
|
|
12622
|
+
const eventBus = useContext24(PanoEventBusContext);
|
|
10001
12623
|
const cursorApi = usePanoCursor();
|
|
10002
12624
|
const { camera, size } = useThree20();
|
|
10003
|
-
const groupRef =
|
|
10004
|
-
const tooltipAnchorRef =
|
|
10005
|
-
const dragStateRef =
|
|
10006
|
-
const suppressNextClickRef =
|
|
12625
|
+
const groupRef = useRef26(null);
|
|
12626
|
+
const tooltipAnchorRef = useRef26(null);
|
|
12627
|
+
const dragStateRef = useRef26(null);
|
|
12628
|
+
const suppressNextClickRef = useRef26(false);
|
|
10007
12629
|
const [hovered, setHovered] = useState13(false);
|
|
10008
12630
|
const [dragging, setDragging] = useState13(false);
|
|
10009
12631
|
const [pinned, setPinned] = useState13(false);
|
|
@@ -10060,14 +12682,14 @@ function HotspotAnchor({
|
|
|
10060
12682
|
});
|
|
10061
12683
|
const tooltipOpen = visible && tooltipContent !== null && isTooltipOpen(tooltipTrigger, hovered, focused, pinned);
|
|
10062
12684
|
const cursorClaimId = hotspotCursorClaimId(id);
|
|
10063
|
-
|
|
12685
|
+
useEffect28(
|
|
10064
12686
|
() => () => {
|
|
10065
12687
|
dragStateRef.current?.releaseInteractionLock();
|
|
10066
12688
|
dragStateRef.current = null;
|
|
10067
12689
|
},
|
|
10068
12690
|
[]
|
|
10069
12691
|
);
|
|
10070
|
-
|
|
12692
|
+
useEffect28(() => {
|
|
10071
12693
|
if (!cursorApi) {
|
|
10072
12694
|
return;
|
|
10073
12695
|
}
|
|
@@ -10089,14 +12711,14 @@ function HotspotAnchor({
|
|
|
10089
12711
|
hovered,
|
|
10090
12712
|
visible
|
|
10091
12713
|
]);
|
|
10092
|
-
|
|
12714
|
+
useEffect28(
|
|
10093
12715
|
() => () => {
|
|
10094
12716
|
cursorApi?.release(cursorClaimId);
|
|
10095
12717
|
},
|
|
10096
12718
|
[cursorApi, cursorClaimId]
|
|
10097
12719
|
);
|
|
10098
|
-
|
|
10099
|
-
|
|
12720
|
+
useEffect28(() => () => focusGeometry.dispose(), [focusGeometry]);
|
|
12721
|
+
useEffect28(() => {
|
|
10100
12722
|
if (tooltipTrigger !== "click") {
|
|
10101
12723
|
setPinned(false);
|
|
10102
12724
|
return;
|
|
@@ -10105,12 +12727,12 @@ function HotspotAnchor({
|
|
|
10105
12727
|
setPinned(false);
|
|
10106
12728
|
});
|
|
10107
12729
|
}, [eventBus, tooltipTrigger]);
|
|
10108
|
-
|
|
12730
|
+
useEffect28(() => {
|
|
10109
12731
|
if (tooltipTrigger !== "hover") {
|
|
10110
12732
|
setHovered(false);
|
|
10111
12733
|
}
|
|
10112
12734
|
}, [tooltipTrigger]);
|
|
10113
|
-
|
|
12735
|
+
useEffect28(() => {
|
|
10114
12736
|
if (acceptsPointer) {
|
|
10115
12737
|
return;
|
|
10116
12738
|
}
|
|
@@ -10455,11 +13077,11 @@ import { jsx as jsx27 } from "react/jsx-runtime";
|
|
|
10455
13077
|
function useHotspotImageTexture(src, onLoad, onError) {
|
|
10456
13078
|
const gl = useThree21((state) => state.gl);
|
|
10457
13079
|
const [texture, setTexture] = useState14(null);
|
|
10458
|
-
const onLoadRef =
|
|
10459
|
-
const onErrorRef =
|
|
13080
|
+
const onLoadRef = useRef27(onLoad);
|
|
13081
|
+
const onErrorRef = useRef27(onError);
|
|
10460
13082
|
onLoadRef.current = onLoad;
|
|
10461
13083
|
onErrorRef.current = onError;
|
|
10462
|
-
|
|
13084
|
+
useEffect29(() => {
|
|
10463
13085
|
let active = true;
|
|
10464
13086
|
setTexture(null);
|
|
10465
13087
|
if (!src) {
|
|
@@ -10497,7 +13119,7 @@ function useHotspotImageTexture(src, onLoad, onError) {
|
|
|
10497
13119
|
active = false;
|
|
10498
13120
|
};
|
|
10499
13121
|
}, [gl, src]);
|
|
10500
|
-
|
|
13122
|
+
useEffect29(
|
|
10501
13123
|
() => () => {
|
|
10502
13124
|
texture?.dispose();
|
|
10503
13125
|
},
|
|
@@ -10519,7 +13141,7 @@ function ImageHotspot({
|
|
|
10519
13141
|
}
|
|
10520
13142
|
|
|
10521
13143
|
// src/hotspot/polygon-hotspot.tsx
|
|
10522
|
-
import { useEffect as
|
|
13144
|
+
import { useEffect as useEffect30, useMemo as useMemo21, useRef as useRef29 } from "react";
|
|
10523
13145
|
import {
|
|
10524
13146
|
BufferGeometry,
|
|
10525
13147
|
DoubleSide as DoubleSide5,
|
|
@@ -10528,20 +13150,20 @@ import {
|
|
|
10528
13150
|
Quaternion as Quaternion4,
|
|
10529
13151
|
ShapeUtils,
|
|
10530
13152
|
Vector2 as Vector27,
|
|
10531
|
-
Vector3 as
|
|
13153
|
+
Vector3 as Vector315
|
|
10532
13154
|
} from "three";
|
|
10533
13155
|
|
|
10534
13156
|
// src/hotspot/hotspot-stroke-line.tsx
|
|
10535
13157
|
import { Line } from "@react-three/drei";
|
|
10536
13158
|
import { useFrame as useFrame14, useThree as useThree22 } from "@react-three/fiber";
|
|
10537
|
-
import { useLayoutEffect as useLayoutEffect5, useRef as
|
|
13159
|
+
import { useLayoutEffect as useLayoutEffect5, useRef as useRef28 } from "react";
|
|
10538
13160
|
import {
|
|
10539
|
-
MathUtils as
|
|
13161
|
+
MathUtils as MathUtils8,
|
|
10540
13162
|
PerspectiveCamera as PerspectiveCamera6,
|
|
10541
|
-
Vector3 as
|
|
13163
|
+
Vector3 as Vector314
|
|
10542
13164
|
} from "three";
|
|
10543
13165
|
import { jsx as jsx28 } from "react/jsx-runtime";
|
|
10544
|
-
var LINE_WORLD_POSITION = new
|
|
13166
|
+
var LINE_WORLD_POSITION = new Vector314();
|
|
10545
13167
|
function applyScreenSpaceDashScale(object, camera, viewportHeight) {
|
|
10546
13168
|
const material = object?.material;
|
|
10547
13169
|
if (!object || typeof material?.dashScale !== "number") {
|
|
@@ -10550,7 +13172,7 @@ function applyScreenSpaceDashScale(object, camera, viewportHeight) {
|
|
|
10550
13172
|
object.getWorldPosition(LINE_WORLD_POSITION);
|
|
10551
13173
|
const depth = Math.max(camera.position.distanceTo(LINE_WORLD_POSITION), 1);
|
|
10552
13174
|
const fov = camera instanceof PerspectiveCamera6 ? camera.fov : 75;
|
|
10553
|
-
material.dashScale = viewportHeight / (2 * Math.tan(
|
|
13175
|
+
material.dashScale = viewportHeight / (2 * Math.tan(MathUtils8.degToRad(fov) * 0.5) * depth);
|
|
10554
13176
|
}
|
|
10555
13177
|
function resolveDash(dashSize, gapSize) {
|
|
10556
13178
|
if (dashSize === void 0 || !Number.isFinite(dashSize) || dashSize <= 0) {
|
|
@@ -10571,7 +13193,7 @@ function HotspotStrokeLine({
|
|
|
10571
13193
|
dashSize,
|
|
10572
13194
|
gapSize
|
|
10573
13195
|
}) {
|
|
10574
|
-
const lineRef =
|
|
13196
|
+
const lineRef = useRef28(null);
|
|
10575
13197
|
const { camera, size } = useThree22();
|
|
10576
13198
|
const dash = resolveDash(dashSize, gapSize);
|
|
10577
13199
|
useLayoutEffect5(() => {
|
|
@@ -10680,7 +13302,7 @@ function polygonContainsDirection(vertices, direction) {
|
|
|
10680
13302
|
}
|
|
10681
13303
|
function fitsHemisphere(vertices) {
|
|
10682
13304
|
const directions = vertices.map((vertex) => panoPositionToVector3(vertex).normalize());
|
|
10683
|
-
const candidates = [new
|
|
13305
|
+
const candidates = [new Vector315()];
|
|
10684
13306
|
for (const direction of directions) {
|
|
10685
13307
|
candidates[0].add(direction);
|
|
10686
13308
|
candidates.push(direction.clone());
|
|
@@ -10704,7 +13326,7 @@ function validatePolygonVertices(vertices) {
|
|
|
10704
13326
|
if (hasSelfIntersection(unwrapped)) {
|
|
10705
13327
|
issues.push({ code: "self_intersection", message: "Polygon edges cannot cross." });
|
|
10706
13328
|
}
|
|
10707
|
-
if (polygonContainsDirection(normalized, new
|
|
13329
|
+
if (polygonContainsDirection(normalized, new Vector315(0, 1, 0)) || polygonContainsDirection(normalized, new Vector315(0, -1, 0))) {
|
|
10708
13330
|
issues.push({ code: "contains_pole", message: "Polygons cannot contain a panorama pole." });
|
|
10709
13331
|
}
|
|
10710
13332
|
if (!fitsHemisphere(normalized)) {
|
|
@@ -10715,7 +13337,7 @@ function validatePolygonVertices(vertices) {
|
|
|
10715
13337
|
function polygonCenter(vertices) {
|
|
10716
13338
|
const sum = vertices.reduce(
|
|
10717
13339
|
(total, vertex) => total.add(panoPositionToVector3(vertex).normalize()),
|
|
10718
|
-
new
|
|
13340
|
+
new Vector315()
|
|
10719
13341
|
);
|
|
10720
13342
|
return sum.lengthSq() > 1e-8 ? vector3ToPanoPosition(sum) : normalizePanoPosition(vertices[0]);
|
|
10721
13343
|
}
|
|
@@ -10724,7 +13346,7 @@ function surfaceQuaternion(position) {
|
|
|
10724
13346
|
const inward = outward.clone().negate();
|
|
10725
13347
|
const pitch = position.pitch * Math.PI / 180;
|
|
10726
13348
|
const yaw = position.yaw * Math.PI / 180;
|
|
10727
|
-
const localUp = new
|
|
13349
|
+
const localUp = new Vector315(
|
|
10728
13350
|
-Math.sin(pitch) * Math.sin(yaw),
|
|
10729
13351
|
Math.cos(pitch),
|
|
10730
13352
|
Math.sin(pitch) * Math.cos(yaw)
|
|
@@ -10737,7 +13359,7 @@ function makeWorldToLocal(center) {
|
|
|
10737
13359
|
return new Matrix43().compose(
|
|
10738
13360
|
panoPositionToVector3(center, POLYGON_RADIUS),
|
|
10739
13361
|
surfaceQuaternion(center),
|
|
10740
|
-
new
|
|
13362
|
+
new Vector315(1, 1, 1)
|
|
10741
13363
|
).invert();
|
|
10742
13364
|
}
|
|
10743
13365
|
function projectedPoint(a, b, c, weightB, weightC, radius, worldToLocal) {
|
|
@@ -10876,12 +13498,12 @@ function PolygonHotspot({
|
|
|
10876
13498
|
[center, valid, vertices]
|
|
10877
13499
|
);
|
|
10878
13500
|
const resolvedStrokeOpacity = Math.max(0, Math.min(strokeOpacity, 1));
|
|
10879
|
-
const startVerticesRef =
|
|
13501
|
+
const startVerticesRef = useRef29(null);
|
|
10880
13502
|
const issuesKey = issues.map((issue) => issue.code).join(",");
|
|
10881
|
-
|
|
13503
|
+
useEffect30(() => {
|
|
10882
13504
|
if (!valid) onInvalid?.(issues);
|
|
10883
13505
|
}, [issues, issuesKey, onInvalid, valid]);
|
|
10884
|
-
|
|
13506
|
+
useEffect30(() => () => fillGeometry?.dispose(), [fillGeometry]);
|
|
10885
13507
|
if (!valid || !center || !fillGeometry || !strokePoints || strokePoints.length < 2) {
|
|
10886
13508
|
return null;
|
|
10887
13509
|
}
|
|
@@ -10961,12 +13583,12 @@ function PolygonHotspot({
|
|
|
10961
13583
|
}
|
|
10962
13584
|
|
|
10963
13585
|
// src/hotspot/polyline-hotspot.tsx
|
|
10964
|
-
import { useEffect as
|
|
13586
|
+
import { useEffect as useEffect31, useMemo as useMemo22, useRef as useRef30 } from "react";
|
|
10965
13587
|
import {
|
|
10966
|
-
MathUtils as
|
|
13588
|
+
MathUtils as MathUtils9,
|
|
10967
13589
|
Matrix4 as Matrix44,
|
|
10968
13590
|
Quaternion as Quaternion5,
|
|
10969
|
-
Vector3 as
|
|
13591
|
+
Vector3 as Vector316
|
|
10970
13592
|
} from "three";
|
|
10971
13593
|
import { jsx as jsx30 } from "react/jsx-runtime";
|
|
10972
13594
|
var POLYLINE_RADIUS = 990;
|
|
@@ -10993,16 +13615,16 @@ function unwrapVertices(vertices) {
|
|
|
10993
13615
|
function polylineCenter(vertices) {
|
|
10994
13616
|
const sum = vertices.reduce(
|
|
10995
13617
|
(total, vertex) => total.add(panoPositionToVector3(vertex).normalize()),
|
|
10996
|
-
new
|
|
13618
|
+
new Vector316()
|
|
10997
13619
|
);
|
|
10998
13620
|
return sum.lengthSq() > 1e-8 ? vector3ToPanoPosition(sum) : normalizePanoPosition(vertices[0]);
|
|
10999
13621
|
}
|
|
11000
13622
|
function surfaceQuaternion2(position) {
|
|
11001
13623
|
const outward = panoPositionToVector3(position).normalize();
|
|
11002
13624
|
const inward = outward.clone().negate();
|
|
11003
|
-
const pitch =
|
|
11004
|
-
const yaw =
|
|
11005
|
-
const localUp = new
|
|
13625
|
+
const pitch = MathUtils9.degToRad(position.pitch);
|
|
13626
|
+
const yaw = MathUtils9.degToRad(position.yaw);
|
|
13627
|
+
const localUp = new Vector316(
|
|
11006
13628
|
-Math.sin(pitch) * Math.sin(yaw),
|
|
11007
13629
|
Math.cos(pitch),
|
|
11008
13630
|
Math.sin(pitch) * Math.cos(yaw)
|
|
@@ -11015,7 +13637,7 @@ function makeWorldToLocal2(center) {
|
|
|
11015
13637
|
return new Matrix44().compose(
|
|
11016
13638
|
panoPositionToVector3(center, POLYLINE_RADIUS),
|
|
11017
13639
|
surfaceQuaternion2(center),
|
|
11018
|
-
new
|
|
13640
|
+
new Vector316(1, 1, 1)
|
|
11019
13641
|
).invert();
|
|
11020
13642
|
}
|
|
11021
13643
|
function subdivisionSteps(vertices) {
|
|
@@ -11030,7 +13652,7 @@ function subdivisionSteps(vertices) {
|
|
|
11030
13652
|
}
|
|
11031
13653
|
return Math.min(
|
|
11032
13654
|
8,
|
|
11033
|
-
Math.max(1, Math.ceil(
|
|
13655
|
+
Math.max(1, Math.ceil(MathUtils9.radToDeg(maxAngle) / MAX_SEGMENT_DEGREES))
|
|
11034
13656
|
);
|
|
11035
13657
|
}
|
|
11036
13658
|
function makeLinePositions(vertices, center) {
|
|
@@ -11093,8 +13715,8 @@ function PolylineHotspot({
|
|
|
11093
13715
|
[center, valid, vertices]
|
|
11094
13716
|
);
|
|
11095
13717
|
const opacity = Math.max(0, Math.min(strokeOpacity, 1));
|
|
11096
|
-
const startVerticesRef =
|
|
11097
|
-
|
|
13718
|
+
const startVerticesRef = useRef30(null);
|
|
13719
|
+
useEffect31(() => {
|
|
11098
13720
|
if (!valid) onInvalid?.(issues);
|
|
11099
13721
|
}, [issues, onInvalid, valid]);
|
|
11100
13722
|
if (!valid || !center || !linePoints || linePoints.length < 2) return null;
|
|
@@ -11160,7 +13782,7 @@ function PolylineHotspot({
|
|
|
11160
13782
|
}
|
|
11161
13783
|
|
|
11162
13784
|
// src/hotspot/graphic-hotspot.tsx
|
|
11163
|
-
import { useEffect as
|
|
13785
|
+
import { useEffect as useEffect32, useRef as useRef31, useState as useState15 } from "react";
|
|
11164
13786
|
import {
|
|
11165
13787
|
CanvasTexture,
|
|
11166
13788
|
ClampToEdgeWrapping as ClampToEdgeWrapping4,
|
|
@@ -11358,11 +13980,11 @@ function createGraphicTexture(graphic, aspectWidth, aspectHeight) {
|
|
|
11358
13980
|
}
|
|
11359
13981
|
function useGraphicTexture(graphic, aspectWidth, aspectHeight, onLoad, onError) {
|
|
11360
13982
|
const [texture, setTexture] = useState15(null);
|
|
11361
|
-
const onLoadRef =
|
|
11362
|
-
const onErrorRef =
|
|
13983
|
+
const onLoadRef = useRef31(onLoad);
|
|
13984
|
+
const onErrorRef = useRef31(onError);
|
|
11363
13985
|
onLoadRef.current = onLoad;
|
|
11364
13986
|
onErrorRef.current = onError;
|
|
11365
|
-
|
|
13987
|
+
useEffect32(() => {
|
|
11366
13988
|
let nextTexture = null;
|
|
11367
13989
|
try {
|
|
11368
13990
|
nextTexture = createGraphicTexture(graphic, aspectWidth, aspectHeight);
|
|
@@ -11401,7 +14023,7 @@ function GraphicHotspot(props) {
|
|
|
11401
14023
|
|
|
11402
14024
|
// src/hotspot/sequence-hotspot.tsx
|
|
11403
14025
|
import { useFrame as useFrame15, useThree as useThree23 } from "@react-three/fiber";
|
|
11404
|
-
import { useEffect as
|
|
14026
|
+
import { useEffect as useEffect33, useRef as useRef32, useState as useState16 } from "react";
|
|
11405
14027
|
import {
|
|
11406
14028
|
ClampToEdgeWrapping as ClampToEdgeWrapping5,
|
|
11407
14029
|
LinearFilter as LinearFilter8,
|
|
@@ -11425,11 +14047,11 @@ function useSpriteTexture({
|
|
|
11425
14047
|
}) {
|
|
11426
14048
|
const gl = useThree23((state) => state.gl);
|
|
11427
14049
|
const [texture, setTexture] = useState16(null);
|
|
11428
|
-
const onErrorRef =
|
|
11429
|
-
const onLoadProgressRef =
|
|
14050
|
+
const onErrorRef = useRef32(onError);
|
|
14051
|
+
const onLoadProgressRef = useRef32(onLoadProgress);
|
|
11430
14052
|
onErrorRef.current = onError;
|
|
11431
14053
|
onLoadProgressRef.current = onLoadProgress;
|
|
11432
|
-
|
|
14054
|
+
useEffect33(() => {
|
|
11433
14055
|
let active = true;
|
|
11434
14056
|
setTexture(null);
|
|
11435
14057
|
if (!src) {
|
|
@@ -11470,7 +14092,7 @@ function useSpriteTexture({
|
|
|
11470
14092
|
active = false;
|
|
11471
14093
|
};
|
|
11472
14094
|
}, [gl, id, src]);
|
|
11473
|
-
|
|
14095
|
+
useEffect33(
|
|
11474
14096
|
() => () => {
|
|
11475
14097
|
texture?.dispose();
|
|
11476
14098
|
},
|
|
@@ -11500,23 +14122,23 @@ function SequenceHotspot({
|
|
|
11500
14122
|
const frameCount = resolveFrameCount(requestedFrameCount);
|
|
11501
14123
|
const safeFps = resolveFps(fps);
|
|
11502
14124
|
const [frameIndex, setFrameIndex] = useState16(0);
|
|
11503
|
-
const elapsedRef =
|
|
11504
|
-
const frameIndexRef =
|
|
11505
|
-
const endedRef =
|
|
11506
|
-
const lastPlaybackStateRef =
|
|
11507
|
-
const onFrameChangeRef =
|
|
11508
|
-
const onPlaybackStateChangeRef =
|
|
11509
|
-
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);
|
|
11510
14132
|
onFrameChangeRef.current = onFrameChange;
|
|
11511
14133
|
onPlaybackStateChangeRef.current = onPlaybackStateChange;
|
|
11512
14134
|
onEndedRef.current = onEnded;
|
|
11513
|
-
|
|
14135
|
+
useEffect33(() => {
|
|
11514
14136
|
elapsedRef.current = 0;
|
|
11515
14137
|
frameIndexRef.current = 0;
|
|
11516
14138
|
endedRef.current = false;
|
|
11517
14139
|
setFrameIndex(0);
|
|
11518
14140
|
}, [frameCount, frameDirection, src]);
|
|
11519
|
-
|
|
14141
|
+
useEffect33(() => {
|
|
11520
14142
|
if (!texture) {
|
|
11521
14143
|
return;
|
|
11522
14144
|
}
|
|
@@ -11530,13 +14152,13 @@ function SequenceHotspot({
|
|
|
11530
14152
|
);
|
|
11531
14153
|
texture.needsUpdate = true;
|
|
11532
14154
|
}, [frameCount, frameDirection, frameIndex, texture]);
|
|
11533
|
-
|
|
14155
|
+
useEffect33(() => {
|
|
11534
14156
|
if (!texture) {
|
|
11535
14157
|
return;
|
|
11536
14158
|
}
|
|
11537
14159
|
onFrameChangeRef.current?.({ id, index: 0, src });
|
|
11538
14160
|
}, [id, src, texture]);
|
|
11539
|
-
|
|
14161
|
+
useEffect33(() => {
|
|
11540
14162
|
if (!texture) {
|
|
11541
14163
|
return;
|
|
11542
14164
|
}
|
|
@@ -11590,7 +14212,7 @@ function SequenceHotspot({
|
|
|
11590
14212
|
|
|
11591
14213
|
// src/hotspot/video-hotspot.tsx
|
|
11592
14214
|
import { useThree as useThree24 } from "@react-three/fiber";
|
|
11593
|
-
import { useEffect as
|
|
14215
|
+
import { useEffect as useEffect34, useRef as useRef33, useState as useState17 } from "react";
|
|
11594
14216
|
import {
|
|
11595
14217
|
ClampToEdgeWrapping as ClampToEdgeWrapping6,
|
|
11596
14218
|
LinearFilter as LinearFilter9,
|
|
@@ -11609,9 +14231,9 @@ function clampVolume2(volume) {
|
|
|
11609
14231
|
function usePosterTexture2(id, poster, onError) {
|
|
11610
14232
|
const gl = useThree24((state) => state.gl);
|
|
11611
14233
|
const [texture, setTexture] = useState17(null);
|
|
11612
|
-
const onErrorRef =
|
|
14234
|
+
const onErrorRef = useRef33(onError);
|
|
11613
14235
|
onErrorRef.current = onError;
|
|
11614
|
-
|
|
14236
|
+
useEffect34(() => {
|
|
11615
14237
|
let active = true;
|
|
11616
14238
|
setTexture(null);
|
|
11617
14239
|
if (!poster) {
|
|
@@ -11648,7 +14270,7 @@ function usePosterTexture2(id, poster, onError) {
|
|
|
11648
14270
|
active = false;
|
|
11649
14271
|
};
|
|
11650
14272
|
}, [gl, id, poster]);
|
|
11651
|
-
|
|
14273
|
+
useEffect34(
|
|
11652
14274
|
() => () => {
|
|
11653
14275
|
texture?.dispose();
|
|
11654
14276
|
},
|
|
@@ -11667,13 +14289,13 @@ function useVideoResource({
|
|
|
11667
14289
|
src
|
|
11668
14290
|
}) {
|
|
11669
14291
|
const [resource, setResource] = useState17(null);
|
|
11670
|
-
const onEndedRef =
|
|
11671
|
-
const onErrorRef =
|
|
11672
|
-
const onPlaybackStateChangeRef =
|
|
14292
|
+
const onEndedRef = useRef33(onEnded);
|
|
14293
|
+
const onErrorRef = useRef33(onError);
|
|
14294
|
+
const onPlaybackStateChangeRef = useRef33(onPlaybackStateChange);
|
|
11673
14295
|
onEndedRef.current = onEnded;
|
|
11674
14296
|
onErrorRef.current = onError;
|
|
11675
14297
|
onPlaybackStateChangeRef.current = onPlaybackStateChange;
|
|
11676
|
-
|
|
14298
|
+
useEffect34(() => {
|
|
11677
14299
|
if (!src) {
|
|
11678
14300
|
setResource(null);
|
|
11679
14301
|
return;
|
|
@@ -11774,11 +14396,11 @@ function VideoHotspot({
|
|
|
11774
14396
|
src
|
|
11775
14397
|
});
|
|
11776
14398
|
const posterTexture = usePosterTexture2(id, poster, onError);
|
|
11777
|
-
const onPlaybackErrorRef =
|
|
11778
|
-
const onPlaybackStateChangeRef =
|
|
14399
|
+
const onPlaybackErrorRef = useRef33(onPlaybackError);
|
|
14400
|
+
const onPlaybackStateChangeRef = useRef33(onPlaybackStateChange);
|
|
11779
14401
|
onPlaybackErrorRef.current = onPlaybackError;
|
|
11780
14402
|
onPlaybackStateChangeRef.current = onPlaybackStateChange;
|
|
11781
|
-
|
|
14403
|
+
useEffect34(() => {
|
|
11782
14404
|
if (!resource) {
|
|
11783
14405
|
return;
|
|
11784
14406
|
}
|
|
@@ -11788,7 +14410,7 @@ function VideoHotspot({
|
|
|
11788
14410
|
resource.video.playsInline = playsInline;
|
|
11789
14411
|
resource.video.preload = preload;
|
|
11790
14412
|
}, [loop, muted, playsInline, preload, resource, volume]);
|
|
11791
|
-
|
|
14413
|
+
useEffect34(() => {
|
|
11792
14414
|
if (!resource) {
|
|
11793
14415
|
return;
|
|
11794
14416
|
}
|
|
@@ -11814,16 +14436,314 @@ function VideoHotspot({
|
|
|
11814
14436
|
return /* @__PURE__ */ jsx33(HotspotAnchor, { ...anchorProps, id, height, width, children: /* @__PURE__ */ jsx33(HotspotPlane, { map: activeTexture, opacity }) });
|
|
11815
14437
|
}
|
|
11816
14438
|
|
|
11817
|
-
// src/hotspot/
|
|
11818
|
-
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";
|
|
11819
14442
|
import {
|
|
11820
14443
|
CanvasTexture as CanvasTexture2,
|
|
11821
14444
|
ClampToEdgeWrapping as ClampToEdgeWrapping7,
|
|
11822
14445
|
LinearFilter as LinearFilter10,
|
|
11823
14446
|
LinearMipmapLinearFilter as LinearMipmapLinearFilter7,
|
|
11824
|
-
SRGBColorSpace as SRGBColorSpace9
|
|
14447
|
+
SRGBColorSpace as SRGBColorSpace9,
|
|
14448
|
+
TextureLoader as TextureLoader8
|
|
11825
14449
|
} from "three";
|
|
11826
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";
|
|
11827
14747
|
var TEXT_TEXTURE_LONG_SIDE = 1024;
|
|
11828
14748
|
var DEFAULT_FONT_FAMILY = "system-ui, sans-serif";
|
|
11829
14749
|
var DEFAULT_FONT_SIZE = 96;
|
|
@@ -12032,23 +14952,23 @@ function createTextTexture(text, width, height, style) {
|
|
|
12032
14952
|
throw new Error("Canvas 2D is unavailable for this text hotspot.");
|
|
12033
14953
|
}
|
|
12034
14954
|
drawTextHotspot(context, canvasWidth, canvasHeight, text, style);
|
|
12035
|
-
const texture = new
|
|
12036
|
-
texture.colorSpace =
|
|
12037
|
-
texture.wrapS =
|
|
12038
|
-
texture.wrapT =
|
|
12039
|
-
texture.magFilter =
|
|
12040
|
-
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;
|
|
12041
14961
|
texture.generateMipmaps = true;
|
|
12042
14962
|
texture.needsUpdate = true;
|
|
12043
14963
|
return texture;
|
|
12044
14964
|
}
|
|
12045
14965
|
function useTextTexture(text, width, height, style, onLoad, onError) {
|
|
12046
|
-
const [texture, setTexture] =
|
|
12047
|
-
const onLoadRef =
|
|
12048
|
-
const onErrorRef =
|
|
14966
|
+
const [texture, setTexture] = useState19(null);
|
|
14967
|
+
const onLoadRef = useRef35(onLoad);
|
|
14968
|
+
const onErrorRef = useRef35(onError);
|
|
12049
14969
|
onLoadRef.current = onLoad;
|
|
12050
14970
|
onErrorRef.current = onError;
|
|
12051
|
-
|
|
14971
|
+
useEffect36(() => {
|
|
12052
14972
|
let cancelled = false;
|
|
12053
14973
|
let nextTexture = null;
|
|
12054
14974
|
const run = async () => {
|
|
@@ -12141,13 +15061,13 @@ function TextHotspot({
|
|
|
12141
15061
|
whiteSpace
|
|
12142
15062
|
};
|
|
12143
15063
|
const texture = useTextTexture(text, width, height, style, onLoad, onError);
|
|
12144
|
-
return /* @__PURE__ */
|
|
15064
|
+
return /* @__PURE__ */ jsx35(HotspotAnchor, { ...anchorProps, height, width, children: /* @__PURE__ */ jsx35(HotspotPlane, { map: texture, opacity }) });
|
|
12145
15065
|
}
|
|
12146
15066
|
|
|
12147
15067
|
// src/hotspot/iframe-hotspot.tsx
|
|
12148
15068
|
import { Html as Html2 } from "@react-three/drei";
|
|
12149
15069
|
import { DoubleSide as DoubleSide6 } from "three";
|
|
12150
|
-
import { jsx as
|
|
15070
|
+
import { jsx as jsx36, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
12151
15071
|
var IFRAME_LONG_SIDE = 800;
|
|
12152
15072
|
var CSS3D_DISTANCE_FACTOR = 400;
|
|
12153
15073
|
var DEFAULT_SANDBOX = "allow-scripts allow-popups allow-forms";
|
|
@@ -12214,8 +15134,8 @@ function IframeHotspot({
|
|
|
12214
15134
|
width,
|
|
12215
15135
|
children: [
|
|
12216
15136
|
/* @__PURE__ */ jsxs19("mesh", { children: [
|
|
12217
|
-
/* @__PURE__ */
|
|
12218
|
-
/* @__PURE__ */
|
|
15137
|
+
/* @__PURE__ */ jsx36("planeGeometry", { args: [1, 1] }),
|
|
15138
|
+
/* @__PURE__ */ jsx36(
|
|
12219
15139
|
"meshBasicMaterial",
|
|
12220
15140
|
{
|
|
12221
15141
|
depthWrite: false,
|
|
@@ -12226,7 +15146,7 @@ function IframeHotspot({
|
|
|
12226
15146
|
}
|
|
12227
15147
|
)
|
|
12228
15148
|
] }),
|
|
12229
|
-
/* @__PURE__ */
|
|
15149
|
+
/* @__PURE__ */ jsx36(
|
|
12230
15150
|
Html2,
|
|
12231
15151
|
{
|
|
12232
15152
|
distanceFactor: CSS3D_DISTANCE_FACTOR,
|
|
@@ -12241,7 +15161,7 @@ function IframeHotspot({
|
|
|
12241
15161
|
},
|
|
12242
15162
|
transform: true,
|
|
12243
15163
|
zIndexRange: [10, 0],
|
|
12244
|
-
children: /* @__PURE__ */
|
|
15164
|
+
children: /* @__PURE__ */ jsx36(
|
|
12245
15165
|
"iframe",
|
|
12246
15166
|
{
|
|
12247
15167
|
allow,
|
|
@@ -12262,7 +15182,9 @@ function IframeHotspot({
|
|
|
12262
15182
|
);
|
|
12263
15183
|
}
|
|
12264
15184
|
export {
|
|
15185
|
+
AudioHotspot,
|
|
12265
15186
|
AutoRotate,
|
|
15187
|
+
BackgroundAudio,
|
|
12266
15188
|
DEFAULT_HOTSPOT_TOOLTIP_APPEARANCE,
|
|
12267
15189
|
DEFAULT_HOTSPOT_TOOLTIP_OFFSET,
|
|
12268
15190
|
DEFAULT_PANO_CURSORS,
|
|
@@ -12313,4 +15235,28 @@ export {
|
|
|
12313
15235
|
validatePolylineVertices,
|
|
12314
15236
|
vector3ToPanoPosition
|
|
12315
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
|
+
*/
|
|
12316
15262
|
//# sourceMappingURL=index.mjs.map
|