@ericchen1990/pano-view 5.0.0 → 5.1.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/dist/index.cjs +293 -138
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.mjs +272 -117
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +4 -3
- package/docs/dialogs.md +4 -0
- package/docs/dialogs.zh-CN.md +4 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2509,6 +2509,19 @@ function createSpatialHost() {
|
|
|
2509
2509
|
}
|
|
2510
2510
|
var SpatialHostContext = (0, import_react.createContext)(null);
|
|
2511
2511
|
|
|
2512
|
+
// src/spatial/model-controls.ts
|
|
2513
|
+
function resolveSurfaceModelAdapter(surface, controls, hovered, previous) {
|
|
2514
|
+
let first = null;
|
|
2515
|
+
let retained = null;
|
|
2516
|
+
for (const [node, adapter] of controls) {
|
|
2517
|
+
if (!surface.contains(node)) continue;
|
|
2518
|
+
first ?? (first = adapter);
|
|
2519
|
+
if (adapter === hovered) return adapter;
|
|
2520
|
+
if (adapter === previous) retained = adapter;
|
|
2521
|
+
}
|
|
2522
|
+
return retained ?? first;
|
|
2523
|
+
}
|
|
2524
|
+
|
|
2512
2525
|
// src/controls/actions.ts
|
|
2513
2526
|
var CONTROL_PATHS = {
|
|
2514
2527
|
play: "M8 5 L19 12 L8 19 Z",
|
|
@@ -2532,6 +2545,7 @@ var CONTROL_PATHS = {
|
|
|
2532
2545
|
function mediaActions(controller, seekSpeed = 10, volumeSpeed = 0.25) {
|
|
2533
2546
|
if (!controller) return [];
|
|
2534
2547
|
const snapshot = () => controller.getSnapshot();
|
|
2548
|
+
const safeVolumeSpeed = Number.isFinite(volumeSpeed) && volumeSpeed >= 0 ? volumeSpeed : 0.25;
|
|
2535
2549
|
return [
|
|
2536
2550
|
{
|
|
2537
2551
|
id: snapshot().playing ? "pause" : "play",
|
|
@@ -2556,22 +2570,25 @@ function mediaActions(controller, seekSpeed = 10, volumeSpeed = 0.25) {
|
|
|
2556
2570
|
)
|
|
2557
2571
|
)
|
|
2558
2572
|
})),
|
|
2559
|
-
...(snapshot().volumeAdjustable ? [-1, 1] : []).map((direction) => ({
|
|
2573
|
+
...(snapshot().hasAudio !== false && snapshot().volumeAdjustable ? [-1, 1] : []).map((direction) => ({
|
|
2560
2574
|
id: direction < 0 ? "vol-" : "vol+",
|
|
2561
2575
|
label: direction < 0 ? "Volume down" : "Volume up",
|
|
2562
|
-
enabled: () => snapshot().volumeAdjustable && (direction < 0 ? snapshot().volume > 0 : snapshot().volume < 1),
|
|
2563
|
-
update: (dt) =>
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
Math.min(1, snapshot().volume + direction * dt *
|
|
2567
|
-
)
|
|
2568
|
-
|
|
2576
|
+
enabled: () => snapshot().hasAudio !== false && snapshot().volumeAdjustable && (direction < 0 ? snapshot().volume > 0 : snapshot().volume < 1),
|
|
2577
|
+
update: (dt) => {
|
|
2578
|
+
if (!Number.isFinite(dt) || dt <= 0 || snapshot().hasAudio === false || !snapshot().volumeAdjustable) return;
|
|
2579
|
+
controller.setVolume(
|
|
2580
|
+
Math.max(0, Math.min(1, snapshot().volume + direction * dt * safeVolumeSpeed))
|
|
2581
|
+
);
|
|
2582
|
+
}
|
|
2569
2583
|
})),
|
|
2570
|
-
{
|
|
2584
|
+
...snapshot().hasAudio === false ? [] : [{
|
|
2571
2585
|
id: snapshot().muted ? "unmute" : "mute",
|
|
2572
2586
|
label: snapshot().muted ? "Unmute" : "Mute",
|
|
2573
|
-
|
|
2574
|
-
|
|
2587
|
+
enabled: () => snapshot().hasAudio !== false,
|
|
2588
|
+
activate: () => {
|
|
2589
|
+
if (snapshot().hasAudio !== false) controller.setMuted(!snapshot().muted);
|
|
2590
|
+
}
|
|
2591
|
+
}]
|
|
2575
2592
|
];
|
|
2576
2593
|
}
|
|
2577
2594
|
function modelActions(adapter, rotateSpeed = 30, zoomSpeed = 1.5) {
|
|
@@ -2710,6 +2727,35 @@ function scrollViewportBounds(root, target, maxHeight) {
|
|
|
2710
2727
|
};
|
|
2711
2728
|
}
|
|
2712
2729
|
|
|
2730
|
+
// src/controls/media-audio.ts
|
|
2731
|
+
function probeMediaHasAudio(media) {
|
|
2732
|
+
if (media.readyState < 1) return void 0;
|
|
2733
|
+
const metadata = media;
|
|
2734
|
+
if ((metadata.audioTracks?.length ?? 0) > 0 || metadata.mozHasAudio === true || (metadata.webkitAudioDecodedByteCount ?? 0) > 0) return true;
|
|
2735
|
+
if (metadata.audioTracks?.length === 0 || metadata.mozHasAudio === false) return false;
|
|
2736
|
+
return void 0;
|
|
2737
|
+
}
|
|
2738
|
+
function subscribeMediaAudio(media, notify2) {
|
|
2739
|
+
let tracks;
|
|
2740
|
+
const trackEvents = ["addtrack", "removetrack", "change"];
|
|
2741
|
+
const sync = () => {
|
|
2742
|
+
const next = media.audioTracks;
|
|
2743
|
+
if (next !== tracks) {
|
|
2744
|
+
trackEvents.forEach((event) => tracks?.removeEventListener(event, notify2));
|
|
2745
|
+
tracks = next;
|
|
2746
|
+
trackEvents.forEach((event) => tracks?.addEventListener(event, notify2));
|
|
2747
|
+
}
|
|
2748
|
+
notify2();
|
|
2749
|
+
};
|
|
2750
|
+
const events = ["loadstart", "emptied", "loadedmetadata", "loadeddata", "playing", "timeupdate"];
|
|
2751
|
+
events.forEach((event) => media.addEventListener(event, sync));
|
|
2752
|
+
sync();
|
|
2753
|
+
return () => {
|
|
2754
|
+
events.forEach((event) => media.removeEventListener(event, sync));
|
|
2755
|
+
trackEvents.forEach((event) => tracks?.removeEventListener(event, notify2));
|
|
2756
|
+
};
|
|
2757
|
+
}
|
|
2758
|
+
|
|
2713
2759
|
// src/video/format.ts
|
|
2714
2760
|
var DEFAULT_PANO_VIDEO_PLAYBACK_RATES = [0.5, 1, 1.25, 1.5, 2];
|
|
2715
2761
|
var MEDIA_PROBE_EPSILON = 1e-3;
|
|
@@ -2839,6 +2885,29 @@ function cueText(cue) {
|
|
|
2839
2885
|
return cue.text.replace(/<[^>]+>/g, "").replace(/\r\n|\r/g, "\n");
|
|
2840
2886
|
}
|
|
2841
2887
|
|
|
2888
|
+
// src/controls/layout.ts
|
|
2889
|
+
var CONTROL_GROUP_DEFAULTS = { size: 48, gap: 8, padding: 8 };
|
|
2890
|
+
function controlGroupLayout(count, width, size = CONTROL_GROUP_DEFAULTS.size, gap = CONTROL_GROUP_DEFAULTS.gap, padding = CONTROL_GROUP_DEFAULTS.padding) {
|
|
2891
|
+
size = Math.max(1, size);
|
|
2892
|
+
gap = Math.max(0, gap);
|
|
2893
|
+
padding = Math.max(0, padding);
|
|
2894
|
+
const columns = Math.max(1, Math.floor((width - 2 * padding + gap) / (size + gap)));
|
|
2895
|
+
const rows = Math.ceil(count / columns);
|
|
2896
|
+
return {
|
|
2897
|
+
height: count ? rows * size + Math.max(0, rows - 1) * gap + 2 * padding : 0,
|
|
2898
|
+
buttons: Array.from({ length: count }, (_, i) => {
|
|
2899
|
+
const row = Math.floor(i / columns), items = Math.min(columns, count - row * columns);
|
|
2900
|
+
return { x: (width - items * size - (items - 1) * gap) / 2 + i % columns * (size + gap), y: padding + row * (size + gap), w: size, h: size };
|
|
2901
|
+
})
|
|
2902
|
+
};
|
|
2903
|
+
}
|
|
2904
|
+
function allowsAutomaticMediaControls(media) {
|
|
2905
|
+
return media.getAttribute("data-pano-media-controls") !== "none";
|
|
2906
|
+
}
|
|
2907
|
+
function shouldPauseSurfaceMedia(connected, registered) {
|
|
2908
|
+
return !connected || !registered;
|
|
2909
|
+
}
|
|
2910
|
+
|
|
2842
2911
|
// src/controls/media.ts
|
|
2843
2912
|
var import_react2 = require("react");
|
|
2844
2913
|
var mediaControllers = /* @__PURE__ */ new WeakMap();
|
|
@@ -2863,6 +2932,7 @@ function usePanoMediaController(ref) {
|
|
|
2863
2932
|
playing: media ? !media.paused && !media.ended : false,
|
|
2864
2933
|
currentTime: media?.currentTime ?? 0,
|
|
2865
2934
|
duration: media?.duration ?? 0,
|
|
2935
|
+
hasAudio: media ? probeMediaHasAudio(media) : void 0,
|
|
2866
2936
|
volume: media?.volume ?? 1,
|
|
2867
2937
|
volumeAdjustable: adjustable.current,
|
|
2868
2938
|
muted: media?.muted ?? true
|
|
@@ -2900,19 +2970,17 @@ function usePanoMediaController(ref) {
|
|
|
2900
2970
|
adjustable.current = probeVolumeAdjustable(media);
|
|
2901
2971
|
const notify2 = () => listeners.current.forEach((fn) => fn());
|
|
2902
2972
|
const events = [
|
|
2903
|
-
"loadedmetadata",
|
|
2904
2973
|
"durationchange",
|
|
2905
|
-
"timeupdate",
|
|
2906
2974
|
"play",
|
|
2907
2975
|
"pause",
|
|
2908
2976
|
"ended",
|
|
2909
2977
|
"volumechange",
|
|
2910
|
-
"error"
|
|
2911
|
-
"emptied"
|
|
2978
|
+
"error"
|
|
2912
2979
|
];
|
|
2913
2980
|
events.forEach((event) => media.addEventListener(event, notify2));
|
|
2914
|
-
notify2
|
|
2981
|
+
const unsubscribeAudio = subscribeMediaAudio(media, notify2);
|
|
2915
2982
|
return () => {
|
|
2983
|
+
unsubscribeAudio();
|
|
2916
2984
|
if (mediaControllers.get(media) === controller) mediaControllers.delete(media);
|
|
2917
2985
|
events.forEach((event) => media.removeEventListener(event, notify2));
|
|
2918
2986
|
};
|
|
@@ -3231,6 +3299,7 @@ function PanoControlGroup({
|
|
|
3231
3299
|
{
|
|
3232
3300
|
...props,
|
|
3233
3301
|
role: "group",
|
|
3302
|
+
style: { gap: `var(--pano-control-gap, ${CONTROL_GROUP_DEFAULTS.gap}px)`, padding: `var(--pano-control-padding, ${CONTROL_GROUP_DEFAULTS.padding}px)`, ...props.style },
|
|
3234
3303
|
"data-pano-control-group": "",
|
|
3235
3304
|
className: `pano-control-group ${props.className ?? ""}`,
|
|
3236
3305
|
children: children ? children(actions) : actions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
@@ -4023,7 +4092,7 @@ function SurfaceMediaControls({ surface }) {
|
|
|
4023
4092
|
const sync = () => {
|
|
4024
4093
|
const videos = [...surface.element.querySelectorAll("video")];
|
|
4025
4094
|
const automatic = videos.filter((video) => {
|
|
4026
|
-
if (explicitTargets.has(mediaControllers.get(video) ?? video)) return false;
|
|
4095
|
+
if (!allowsAutomaticMediaControls(video) || explicitTargets.has(mediaControllers.get(video) ?? video)) return false;
|
|
4027
4096
|
return ![...host.controls].some(([node]) => node === video || node.contains(video));
|
|
4028
4097
|
});
|
|
4029
4098
|
let changed = false;
|
|
@@ -4096,7 +4165,7 @@ function makeCanvas() {
|
|
|
4096
4165
|
canvas.height = HEIGHT * RASTER_SCALE;
|
|
4097
4166
|
return canvas;
|
|
4098
4167
|
}
|
|
4099
|
-
async function capture(element, owner) {
|
|
4168
|
+
async function capture(element, owner, footer = false) {
|
|
4100
4169
|
const canvas = document.createElement("canvas");
|
|
4101
4170
|
const ctx = canvas.getContext("2d");
|
|
4102
4171
|
const native = ctx;
|
|
@@ -4130,6 +4199,10 @@ async function capture(element, owner) {
|
|
|
4130
4199
|
transform: "none",
|
|
4131
4200
|
position: "relative"
|
|
4132
4201
|
});
|
|
4202
|
+
if (footer) {
|
|
4203
|
+
clone2.style.borderBottomLeftRadius = "0";
|
|
4204
|
+
clone2.style.borderBottomRightRadius = "0";
|
|
4205
|
+
}
|
|
4133
4206
|
clone2.setAttribute("drawable", "");
|
|
4134
4207
|
canvas.append(clone2);
|
|
4135
4208
|
owner.append(canvas);
|
|
@@ -4224,6 +4297,10 @@ async function capture(element, owner) {
|
|
|
4224
4297
|
top: "0",
|
|
4225
4298
|
transform: "none"
|
|
4226
4299
|
});
|
|
4300
|
+
if (footer) {
|
|
4301
|
+
clone.style.borderBottomLeftRadius = "0";
|
|
4302
|
+
clone.style.borderBottomRightRadius = "0";
|
|
4303
|
+
}
|
|
4227
4304
|
owner.append(clone);
|
|
4228
4305
|
originals.forEach((node, i) => {
|
|
4229
4306
|
copies[i].scrollTop = node.scrollTop;
|
|
@@ -4301,6 +4378,7 @@ function SurfacePanel({ surface }) {
|
|
|
4301
4378
|
edgeButtons: [],
|
|
4302
4379
|
target: surface.element,
|
|
4303
4380
|
adapter: null,
|
|
4381
|
+
modelAdapter: null,
|
|
4304
4382
|
scrollTarget: null,
|
|
4305
4383
|
mediaTarget: null
|
|
4306
4384
|
});
|
|
@@ -4311,7 +4389,7 @@ function SurfacePanel({ surface }) {
|
|
|
4311
4389
|
controller = {
|
|
4312
4390
|
subscribe: () => () => {
|
|
4313
4391
|
},
|
|
4314
|
-
getSnapshot: () => ({ ready: media.readyState >= 1, playing: !media.paused && !media.ended, currentTime: media.currentTime, duration: media.duration, volume: media.volume, volumeAdjustable: volumeCapabilities.get(media) ?? false, muted: media.muted }),
|
|
4392
|
+
getSnapshot: () => ({ ready: media.readyState >= 1, playing: !media.paused && !media.ended, currentTime: media.currentTime, duration: media.duration, hasAudio: probeMediaHasAudio(media), volume: media.volume, volumeAdjustable: volumeCapabilities.get(media) ?? false, muted: media.muted }),
|
|
4315
4393
|
play: async () => {
|
|
4316
4394
|
try {
|
|
4317
4395
|
await media.play();
|
|
@@ -4328,7 +4406,7 @@ function SurfacePanel({ surface }) {
|
|
|
4328
4406
|
if (Number.isFinite(time) && Number.isFinite(media.duration)) media.currentTime = Math.max(0, Math.min(media.duration, time));
|
|
4329
4407
|
},
|
|
4330
4408
|
setVolume: (value) => {
|
|
4331
|
-
media.volume = value;
|
|
4409
|
+
if (Number.isFinite(value) && volumeCapabilities.get(media)) media.volume = clampVolume(value);
|
|
4332
4410
|
},
|
|
4333
4411
|
setMuted: (value) => {
|
|
4334
4412
|
media.muted = value;
|
|
@@ -4345,6 +4423,7 @@ function SurfacePanel({ surface }) {
|
|
|
4345
4423
|
s.generation++;
|
|
4346
4424
|
s.target = surface.element;
|
|
4347
4425
|
s.adapter = null;
|
|
4426
|
+
s.modelAdapter = null;
|
|
4348
4427
|
s.dirty = true;
|
|
4349
4428
|
s.image = null;
|
|
4350
4429
|
s.mediaBlocked = false;
|
|
@@ -4424,7 +4503,7 @@ function SurfacePanel({ surface }) {
|
|
|
4424
4503
|
videos.current.clear();
|
|
4425
4504
|
controllers.current.clear();
|
|
4426
4505
|
blockedMedia.current = /* @__PURE__ */ new WeakSet();
|
|
4427
|
-
surface.element.querySelectorAll("video,audio").forEach((m) => m.pause());
|
|
4506
|
+
if (shouldPauseSurfaceMedia(surface.element.isConnected, host.surfaces.has(surface))) surface.element.querySelectorAll("video,audio").forEach((m) => m.pause());
|
|
4428
4507
|
};
|
|
4429
4508
|
}, [surface, camera, gl, host, sceneHost, scratch]);
|
|
4430
4509
|
(0, import_react9.useEffect)(
|
|
@@ -4542,9 +4621,15 @@ function SurfacePanel({ surface }) {
|
|
|
4542
4621
|
s.dirty = true;
|
|
4543
4622
|
}
|
|
4544
4623
|
const ctx = canvas.getContext("2d");
|
|
4624
|
+
const appearance = getComputedStyle(surface.element);
|
|
4625
|
+
const token = (name, fallback) => {
|
|
4626
|
+
const value = parseFloat(appearance.getPropertyValue(`--pano-control-${name}`));
|
|
4627
|
+
return Number.isFinite(value) ? value : fallback;
|
|
4628
|
+
};
|
|
4629
|
+
const controlSize = token("size", CONTROL_GROUP_DEFAULTS.size), controlGap = token("gap", CONTROL_GROUP_DEFAULTS.gap), controlPadding = token("padding", CONTROL_GROUP_DEFAULTS.padding);
|
|
4545
4630
|
const nextHeight = Math.max(
|
|
4546
4631
|
surface.anchor ? 1 : 200,
|
|
4547
|
-
Math.min(BODY_HEIGHT, surface.element.offsetHeight) + (s.buttons.length ?
|
|
4632
|
+
Math.min(BODY_HEIGHT, surface.element.offsetHeight) + (s.buttons.length ? controlGroupLayout(s.buttons.length, WIDTH, controlSize, controlGap, controlPadding).height : 0)
|
|
4548
4633
|
);
|
|
4549
4634
|
if (canvas.height !== nextHeight * RASTER_SCALE) {
|
|
4550
4635
|
texture.dispose();
|
|
@@ -4581,7 +4666,7 @@ function SurfacePanel({ surface }) {
|
|
|
4581
4666
|
});
|
|
4582
4667
|
owner.setAttribute("aria-hidden", "true");
|
|
4583
4668
|
surface.element.closest("[data-pano-viewer]")?.append(owner);
|
|
4584
|
-
capture(surface.element, owner).then((image) => {
|
|
4669
|
+
capture(surface.element, owner, s.buttons.length > 0).then((image) => {
|
|
4585
4670
|
if (!s.disposed && generation === s.generation && revision === s.revision) {
|
|
4586
4671
|
s.image = image;
|
|
4587
4672
|
s.failed = false;
|
|
@@ -4597,7 +4682,6 @@ function SurfacePanel({ surface }) {
|
|
|
4597
4682
|
s.busy = false;
|
|
4598
4683
|
});
|
|
4599
4684
|
}
|
|
4600
|
-
const appearance = getComputedStyle(surface.element);
|
|
4601
4685
|
const radius = Math.max(0, parseFloat(appearance.borderTopLeftRadius) || 0);
|
|
4602
4686
|
ctx.clearRect(0, 0, WIDTH, s.height);
|
|
4603
4687
|
ctx.save();
|
|
@@ -4746,31 +4830,55 @@ function SurfacePanel({ surface }) {
|
|
|
4746
4830
|
s.edgeButtons = !host.input.hasStick && !surface.anchor && s.scrollTarget && !explicitTargets.has(s.scrollTarget) ? scrollEdges(s.scrollTarget, scrollViewportBounds(surface.element, s.scrollTarget, Math.min(BODY_HEIGHT, surface.element.offsetHeight)), () => {
|
|
4747
4831
|
s.dirty = true;
|
|
4748
4832
|
}) : [];
|
|
4749
|
-
const adapter = s.adapter;
|
|
4833
|
+
const adapter = resolveSurfaceModelAdapter(surface.element, host.controls, s.adapter, s.modelAdapter);
|
|
4834
|
+
s.modelAdapter = adapter;
|
|
4750
4835
|
if (adapter && !explicitTargets.has(adapter)) for (const action of modelActions(adapter)) {
|
|
4751
4836
|
if (host.input.canDrag && adapter.rotateBy && ["left", "right", "up", "down"].includes(action.id) || host.input.hasStick && adapter.zoomBy && ["in", "out"].includes(action.id)) continue;
|
|
4752
4837
|
add(action.id, action.label, action.update, action.activate, action.enabled);
|
|
4753
4838
|
}
|
|
4754
|
-
if (media instanceof HTMLAudioElement && !adapter && !explicitTargets.has(mediaControllers.get(media) ?? media)) {
|
|
4839
|
+
if (media instanceof HTMLAudioElement && allowsAutomaticMediaControls(media) && !adapter && !explicitTargets.has(mediaControllers.get(media) ?? media)) {
|
|
4755
4840
|
for (const action of mediaActions(controllerFor(media))) add(action.id === "pause" ? "play" : action.id === "unmute" ? "mute" : action.id, action.label, action.update, action.activate, action.enabled);
|
|
4756
4841
|
}
|
|
4757
|
-
s.buttons = surface.anchor ? [] : buttons;
|
|
4758
4842
|
if (surface.anchor) buttons.length = 0;
|
|
4843
|
+
const layout = controlGroupLayout(buttons.length, WIDTH, controlSize, controlGap, controlPadding);
|
|
4844
|
+
const bodyHeight = Math.min(BODY_HEIGHT, surface.element.offsetHeight);
|
|
4845
|
+
buttons.forEach((button, i) => Object.assign(button, layout.buttons[i], { y: bodyHeight + layout.buttons[i].y }));
|
|
4846
|
+
if (s.buttons.length !== buttons.length) s.dirty = true;
|
|
4847
|
+
s.buttons = buttons;
|
|
4848
|
+
if (buttons.length) {
|
|
4849
|
+
ctx.fillStyle = "#161b22";
|
|
4850
|
+
ctx.fillRect(0, bodyHeight, WIDTH, layout.height);
|
|
4851
|
+
}
|
|
4759
4852
|
for (const b of buttons) {
|
|
4760
|
-
ctx.
|
|
4761
|
-
ctx.
|
|
4762
|
-
ctx.fillStyle = "#
|
|
4853
|
+
ctx.save();
|
|
4854
|
+
ctx.globalAlpha = b.action.enabled?.() === false ? 0.4 : 1;
|
|
4855
|
+
ctx.fillStyle = appearance.getPropertyValue("--pano-control-background").trim() || "#39424e";
|
|
4856
|
+
ctx.beginPath();
|
|
4857
|
+
ctx.roundRect(b.x, b.y, b.w, b.h, token("radius", b.w / 2));
|
|
4858
|
+
ctx.fill();
|
|
4859
|
+
const border = /^(\d+(?:\.\d+)?)px\s+solid\s+(.+)$/.exec(appearance.getPropertyValue("--pano-control-border").trim() || "1px solid #68778a");
|
|
4860
|
+
if (border) {
|
|
4861
|
+
ctx.strokeStyle = border[2];
|
|
4862
|
+
ctx.lineWidth = Number(border[1]);
|
|
4863
|
+
ctx.stroke();
|
|
4864
|
+
}
|
|
4865
|
+
if (host.action?.id === b.action.id) {
|
|
4866
|
+
ctx.strokeStyle = appearance.getPropertyValue("--pano-control-focus").trim() || "#ffb300";
|
|
4867
|
+
ctx.lineWidth = 3;
|
|
4868
|
+
ctx.stroke();
|
|
4869
|
+
}
|
|
4763
4870
|
const id = String(b.action.id).replace("scroll-", "");
|
|
4764
4871
|
const icon = id === "play" && media && !media.paused ? "pause" : id === "mute" && media?.muted ? "unmute" : id;
|
|
4765
4872
|
ctx.save();
|
|
4766
|
-
ctx.translate(b.x + b.w / 2 -
|
|
4767
|
-
ctx.scale(
|
|
4768
|
-
ctx.strokeStyle = "#
|
|
4873
|
+
ctx.translate(b.x + b.w / 2 - 12, b.y + b.h / 2 - 12);
|
|
4874
|
+
ctx.scale(1, 1);
|
|
4875
|
+
ctx.strokeStyle = appearance.getPropertyValue("--pano-control-color").trim() || "#baf5ff";
|
|
4769
4876
|
ctx.lineWidth = 2;
|
|
4770
4877
|
ctx.lineCap = "round";
|
|
4771
4878
|
ctx.lineJoin = "round";
|
|
4772
4879
|
ctx.stroke(new Path2D(CONTROL_PATHS[icon] ?? CONTROL_PATHS.reset));
|
|
4773
4880
|
ctx.restore();
|
|
4881
|
+
ctx.restore();
|
|
4774
4882
|
}
|
|
4775
4883
|
for (const button of s.edgeButtons) {
|
|
4776
4884
|
const focused = host.action?.id === button.action.id || [...contacts.current.values()].some((contact) => contact.action?.id === button.action.id);
|
|
@@ -9696,6 +9804,7 @@ function VolumeControl({
|
|
|
9696
9804
|
const mutedOrSilent = muted || volume === 0;
|
|
9697
9805
|
(0, import_react30.useEffect)(() => {
|
|
9698
9806
|
onOpenChange(open);
|
|
9807
|
+
return () => onOpenChange(false);
|
|
9699
9808
|
}, [onOpenChange, open]);
|
|
9700
9809
|
(0, import_react30.useEffect)(() => {
|
|
9701
9810
|
if (!open || !volumeAdjustable || hasFinePointerHover()) {
|
|
@@ -10143,7 +10252,7 @@ function PanoVideoControlsHud({
|
|
|
10143
10252
|
}
|
|
10144
10253
|
),
|
|
10145
10254
|
hideTime ? null : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "pano-video-time", children: formatMediaTime(duration) }),
|
|
10146
|
-
/* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
10255
|
+
snapshot.hasAudio === false ? null : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
10147
10256
|
VolumeControl,
|
|
10148
10257
|
{
|
|
10149
10258
|
appearance: resolved,
|
|
@@ -15086,6 +15195,32 @@ function suppressFollowingClick(target) {
|
|
|
15086
15195
|
setTimeout(cleanup, CLICK_SUPPRESS_MS);
|
|
15087
15196
|
}
|
|
15088
15197
|
|
|
15198
|
+
// src/hotspot/tooltip-layout.ts
|
|
15199
|
+
function tooltipPadding(value) {
|
|
15200
|
+
const values = String(value).trim().split(/\s+/).map((value2) => Math.max(0, parseFloat(value2) || 0));
|
|
15201
|
+
const [top = 0, right2 = top, bottom = top, left = right2] = values;
|
|
15202
|
+
return [top, right2, bottom, left];
|
|
15203
|
+
}
|
|
15204
|
+
function tooltipBaseline(top, lineHeight, ascent, descent) {
|
|
15205
|
+
return top + (lineHeight - ascent - descent) / 2 + ascent;
|
|
15206
|
+
}
|
|
15207
|
+
function tooltipLines(text, maxWidth, measure) {
|
|
15208
|
+
const lines = [];
|
|
15209
|
+
if (!text) return lines;
|
|
15210
|
+
for (const paragraph of text.split("\n")) {
|
|
15211
|
+
let line = "";
|
|
15212
|
+
for (const char of paragraph) {
|
|
15213
|
+
if (line && measure(line + char) > maxWidth) {
|
|
15214
|
+
lines.push(line);
|
|
15215
|
+
line = "";
|
|
15216
|
+
}
|
|
15217
|
+
line += char;
|
|
15218
|
+
}
|
|
15219
|
+
lines.push(line);
|
|
15220
|
+
}
|
|
15221
|
+
return lines;
|
|
15222
|
+
}
|
|
15223
|
+
|
|
15089
15224
|
// src/hotspot/tooltip-transform.ts
|
|
15090
15225
|
var import_three22 = require("three");
|
|
15091
15226
|
var point = new import_three22.Vector3();
|
|
@@ -15179,25 +15314,17 @@ function SpatialHotspotTooltip({
|
|
|
15179
15314
|
}, [content.image]);
|
|
15180
15315
|
const raster = (0, import_react47.useMemo)(() => {
|
|
15181
15316
|
const fontSize = Math.max(1, number(appearance.fontSize, 12));
|
|
15182
|
-
const
|
|
15317
|
+
const [pt, pr, pb, pl] = tooltipPadding(appearance.padding);
|
|
15318
|
+
const padding = Math.max(pl, pr);
|
|
15319
|
+
const letterSpacing = appearance.letterSpacing === "normal" ? 0 : number(appearance.letterSpacing ?? 0, 0);
|
|
15183
15320
|
const leading = appearance.lineHeight;
|
|
15184
15321
|
const lineHeight = typeof leading === "string" && leading.endsWith("px") ? number(leading, fontSize * 1.4) : fontSize * number(leading, 1.4) / (typeof leading === "string" && leading.endsWith("%") ? 100 : 1);
|
|
15185
15322
|
const canvas = document.createElement("canvas");
|
|
15186
15323
|
const ctx = canvas.getContext("2d");
|
|
15187
15324
|
const font = `${fontSize}px ${appearance.fontFamily}`;
|
|
15188
15325
|
ctx.font = font;
|
|
15189
|
-
const
|
|
15190
|
-
|
|
15191
|
-
let line = "";
|
|
15192
|
-
for (const char of paragraph) {
|
|
15193
|
-
if (line && ctx.measureText(line + char).width > 220 - padding * 2) {
|
|
15194
|
-
lines.push(line);
|
|
15195
|
-
line = "";
|
|
15196
|
-
}
|
|
15197
|
-
line += char;
|
|
15198
|
-
}
|
|
15199
|
-
if (line || content.text) lines.push(line);
|
|
15200
|
-
}
|
|
15326
|
+
const measure = (text) => (letterSpacing ? [...text].reduce((width2, char) => width2 + ctx.measureText(char).width, 0) : ctx.measureText(text).width) + Math.max(0, [...text].length - 1) * letterSpacing;
|
|
15327
|
+
const lines = tooltipLines(content.text ?? "", 220 - pl - pr, measure);
|
|
15201
15328
|
const imageWidth = image ? Math.min(
|
|
15202
15329
|
220 - padding * 2,
|
|
15203
15330
|
120 * image.naturalWidth / image.naturalHeight
|
|
@@ -15206,12 +15333,12 @@ function SpatialHotspotTooltip({
|
|
|
15206
15333
|
const width = Math.ceil(
|
|
15207
15334
|
Math.max(
|
|
15208
15335
|
imageWidth,
|
|
15209
|
-
...lines.map(
|
|
15336
|
+
...lines.map(measure),
|
|
15210
15337
|
1
|
|
15211
|
-
) +
|
|
15338
|
+
) + pl + pr
|
|
15212
15339
|
);
|
|
15213
15340
|
const height = Math.ceil(
|
|
15214
|
-
|
|
15341
|
+
pt + pb + imageHeight + (image && lines.length ? padding : 0) + lines.length * lineHeight
|
|
15215
15342
|
);
|
|
15216
15343
|
canvas.width = width * 2;
|
|
15217
15344
|
canvas.height = height * 2;
|
|
@@ -15234,17 +15361,26 @@ function SpatialHotspotTooltip({
|
|
|
15234
15361
|
}
|
|
15235
15362
|
ctx.save();
|
|
15236
15363
|
ctx.clip();
|
|
15237
|
-
let top =
|
|
15364
|
+
let top = pt;
|
|
15238
15365
|
if (image) {
|
|
15239
|
-
ctx.drawImage(image,
|
|
15366
|
+
ctx.drawImage(image, pl, top, imageWidth, imageHeight);
|
|
15240
15367
|
top += imageHeight + padding;
|
|
15241
15368
|
}
|
|
15242
15369
|
ctx.font = font;
|
|
15243
15370
|
ctx.fillStyle = appearance.color;
|
|
15244
|
-
ctx.textBaseline = "
|
|
15245
|
-
lines.forEach(
|
|
15246
|
-
|
|
15247
|
-
|
|
15371
|
+
ctx.textBaseline = "alphabetic";
|
|
15372
|
+
lines.forEach((line, i) => {
|
|
15373
|
+
const metrics = ctx.measureText(line || "Mg");
|
|
15374
|
+
const ascent = metrics.actualBoundingBoxAscent || fontSize * 0.8;
|
|
15375
|
+
const descent = metrics.actualBoundingBoxDescent ?? fontSize * 0.2;
|
|
15376
|
+
let x = pl;
|
|
15377
|
+
const y = tooltipBaseline(top + i * lineHeight, lineHeight, ascent, descent);
|
|
15378
|
+
if (!letterSpacing) ctx.fillText(line, x, y);
|
|
15379
|
+
else for (const char of line) {
|
|
15380
|
+
ctx.fillText(char, x, y);
|
|
15381
|
+
x += ctx.measureText(char).width + letterSpacing;
|
|
15382
|
+
}
|
|
15383
|
+
});
|
|
15248
15384
|
ctx.restore();
|
|
15249
15385
|
const texture = new import_three23.CanvasTexture(canvas);
|
|
15250
15386
|
texture.colorSpace = import_three23.SRGBColorSpace;
|
|
@@ -19291,7 +19427,7 @@ function BackgroundAudio({
|
|
|
19291
19427
|
setInternalPlaying((prev) => !prev);
|
|
19292
19428
|
},
|
|
19293
19429
|
setVolume: (vol) => {
|
|
19294
|
-
if (isControlledRef.current) {
|
|
19430
|
+
if (isControlledRef.current || !Number.isFinite(vol)) {
|
|
19295
19431
|
return;
|
|
19296
19432
|
}
|
|
19297
19433
|
const next = clampAudioVolume(vol);
|
|
@@ -20629,21 +20765,34 @@ function subscribeWebVRPresentationExit(element, onExit) {
|
|
|
20629
20765
|
});
|
|
20630
20766
|
}
|
|
20631
20767
|
|
|
20768
|
+
// src/webvr/reticle-geometry.ts
|
|
20769
|
+
var import_three41 = require("three");
|
|
20770
|
+
function createReticleRing(inner, outer) {
|
|
20771
|
+
const geometry = new import_three41.RingGeometry(inner, outer, 96, 1, Math.PI / 2, -Math.PI * 2);
|
|
20772
|
+
const source = geometry.index;
|
|
20773
|
+
const indices = [];
|
|
20774
|
+
for (let segment = 0; segment < 96; segment++) {
|
|
20775
|
+
if (segment % 4 >= 2) continue;
|
|
20776
|
+
for (let vertex = 0; vertex < 6; vertex++) indices.push(source.getX(segment * 6 + vertex));
|
|
20777
|
+
}
|
|
20778
|
+
geometry.setIndex(indices);
|
|
20779
|
+
return geometry;
|
|
20780
|
+
}
|
|
20781
|
+
|
|
20632
20782
|
// src/webvr/reticle.tsx
|
|
20633
20783
|
var import_fiber31 = require("@react-three/fiber");
|
|
20634
20784
|
var import_react65 = require("react");
|
|
20635
|
-
var
|
|
20785
|
+
var import_three42 = require("three");
|
|
20636
20786
|
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
20637
|
-
var CENTER_NDC = new
|
|
20787
|
+
var CENTER_NDC = new import_three42.Vector2(0, 0);
|
|
20638
20788
|
var HUD_DISTANCE = 2;
|
|
20639
20789
|
var RETICLE_SCALE = 1;
|
|
20640
20790
|
var MOBILE_VR_RETICLE_SCALE = 3;
|
|
20641
20791
|
var RETICLE_RENDER_ORDER = 1e5;
|
|
20642
20792
|
var CROSSHAIR_LENGTH = 0.044;
|
|
20643
|
-
var CROSSHAIR_THICKNESS =
|
|
20793
|
+
var CROSSHAIR_THICKNESS = 6e-3;
|
|
20644
20794
|
var RING_INNER_RADIUS = 0.05;
|
|
20645
20795
|
var RING_OUTER_RADIUS = 0.058;
|
|
20646
|
-
var RING_SEGMENTS = 96;
|
|
20647
20796
|
var RING_INDICES_PER_SEGMENT = 6;
|
|
20648
20797
|
var GAZE_POINTER_ID = 1000001;
|
|
20649
20798
|
var DEFAULT_WEBVR_CURSOR_DWELL_MS = 1500;
|
|
@@ -20725,8 +20874,17 @@ function WebVRReticle({
|
|
|
20725
20874
|
}, []);
|
|
20726
20875
|
const groupRef = (0, import_react65.useRef)(null);
|
|
20727
20876
|
const ringMeshRef = (0, import_react65.useRef)(null);
|
|
20728
|
-
const
|
|
20729
|
-
const
|
|
20877
|
+
const ringBackdropRef = (0, import_react65.useRef)(null);
|
|
20878
|
+
const rings = (0, import_react65.useMemo)(() => ({
|
|
20879
|
+
outline: createReticleRing(RING_INNER_RADIUS - 3e-3, RING_OUTER_RADIUS + 3e-3),
|
|
20880
|
+
track: createReticleRing(RING_INNER_RADIUS, RING_OUTER_RADIUS),
|
|
20881
|
+
progress: createReticleRing(RING_INNER_RADIUS, RING_OUTER_RADIUS)
|
|
20882
|
+
}), []);
|
|
20883
|
+
(0, import_react65.useEffect)(() => () => {
|
|
20884
|
+
Object.values(rings).forEach((geometry) => geometry.dispose());
|
|
20885
|
+
}, [rings]);
|
|
20886
|
+
const directionRef = (0, import_react65.useRef)(new import_three42.Vector3());
|
|
20887
|
+
const raycasterRef = (0, import_react65.useRef)(new import_three42.Raycaster());
|
|
20730
20888
|
const hoveredRef = (0, import_react65.useRef)(null);
|
|
20731
20889
|
const dwellRef = (0, import_react65.useRef)(0);
|
|
20732
20890
|
const clickedRef = (0, import_react65.useRef)(false);
|
|
@@ -20751,6 +20909,7 @@ function WebVRReticle({
|
|
|
20751
20909
|
}
|
|
20752
20910
|
dwellRef.current = 0;
|
|
20753
20911
|
clickedRef.current = false;
|
|
20912
|
+
if (ringBackdropRef.current) ringBackdropRef.current.visible = false;
|
|
20754
20913
|
if (ringMesh) {
|
|
20755
20914
|
ringMesh.visible = false;
|
|
20756
20915
|
ringMesh.geometry.setDrawRange(0, 0);
|
|
@@ -20813,8 +20972,9 @@ function WebVRReticle({
|
|
|
20813
20972
|
dwellRef.current = 0;
|
|
20814
20973
|
}
|
|
20815
20974
|
const progress = spatialOpen ? spatialProgress : target && !clickedRef.current ? resolvedDwellMs > 0 ? Math.min(dwellRef.current / resolvedDwellMs, 1) : 1 : 0;
|
|
20975
|
+
if (ringBackdropRef.current) ringBackdropRef.current.visible = progress > 1e-3;
|
|
20816
20976
|
if (ringMesh) {
|
|
20817
|
-
const segments = Math.max(0, Math.ceil(progress *
|
|
20977
|
+
const segments = Math.max(0, Math.ceil(progress * rings.progress.index.count / RING_INDICES_PER_SEGMENT));
|
|
20818
20978
|
ringMesh.visible = progress > 1e-3;
|
|
20819
20979
|
ringMesh.geometry.setDrawRange(0, segments * RING_INDICES_PER_SEGMENT);
|
|
20820
20980
|
}
|
|
@@ -20830,6 +20990,14 @@ function WebVRReticle({
|
|
|
20830
20990
|
renderOrder: RETICLE_RENDER_ORDER,
|
|
20831
20991
|
visible,
|
|
20832
20992
|
children: [
|
|
20993
|
+
[false, true].map((vertical) => /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("mesh", { frustumCulled: false, raycast: noopRaycast, renderOrder: RETICLE_RENDER_ORDER, children: [
|
|
20994
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("boxGeometry", { args: vertical ? [CROSSHAIR_THICKNESS + 6e-3, CROSSHAIR_LENGTH + 6e-3, 1e-3] : [CROSSHAIR_LENGTH + 6e-3, CROSSHAIR_THICKNESS + 6e-3, 1e-3] }),
|
|
20995
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("meshBasicMaterial", { color: "#101419", transparent: true, depthTest: false, depthWrite: false, toneMapped: false })
|
|
20996
|
+
] }, String(vertical))),
|
|
20997
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)("group", { ref: ringBackdropRef, renderOrder: RETICLE_RENDER_ORDER, visible: false, children: [
|
|
20998
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("mesh", { geometry: rings.outline, frustumCulled: false, raycast: noopRaycast, renderOrder: RETICLE_RENDER_ORDER, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("meshBasicMaterial", { color: "#101419", transparent: true, side: import_three42.DoubleSide, depthTest: false, depthWrite: false, toneMapped: false }) }),
|
|
20999
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)("mesh", { geometry: rings.track, frustumCulled: false, raycast: noopRaycast, renderOrder: RETICLE_RENDER_ORDER + 1, children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("meshBasicMaterial", { color: "#ffffff", transparent: true, opacity: 0.45, side: import_three42.DoubleSide, depthTest: false, depthWrite: false, toneMapped: false }) })
|
|
21000
|
+
] }),
|
|
20833
21001
|
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
|
|
20834
21002
|
"mesh",
|
|
20835
21003
|
{
|
|
@@ -20872,40 +21040,26 @@ function WebVRReticle({
|
|
|
20872
21040
|
]
|
|
20873
21041
|
}
|
|
20874
21042
|
),
|
|
20875
|
-
/* @__PURE__ */ (0, import_jsx_runtime44.
|
|
21043
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
20876
21044
|
"mesh",
|
|
20877
21045
|
{
|
|
20878
21046
|
frustumCulled: false,
|
|
20879
21047
|
raycast: noopRaycast,
|
|
20880
21048
|
ref: ringMeshRef,
|
|
21049
|
+
geometry: rings.progress,
|
|
20881
21050
|
renderOrder: RETICLE_RENDER_ORDER + 2,
|
|
20882
21051
|
visible: false,
|
|
20883
|
-
children:
|
|
20884
|
-
|
|
20885
|
-
|
|
20886
|
-
|
|
20887
|
-
|
|
20888
|
-
|
|
20889
|
-
|
|
20890
|
-
|
|
20891
|
-
|
|
20892
|
-
|
|
20893
|
-
|
|
20894
|
-
]
|
|
20895
|
-
}
|
|
20896
|
-
),
|
|
20897
|
-
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
20898
|
-
"meshBasicMaterial",
|
|
20899
|
-
{
|
|
20900
|
-
color: "#ffffff",
|
|
20901
|
-
depthTest: false,
|
|
20902
|
-
depthWrite: false,
|
|
20903
|
-
side: import_three41.DoubleSide,
|
|
20904
|
-
toneMapped: false,
|
|
20905
|
-
transparent: true
|
|
20906
|
-
}
|
|
20907
|
-
)
|
|
20908
|
-
]
|
|
21052
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
21053
|
+
"meshBasicMaterial",
|
|
21054
|
+
{
|
|
21055
|
+
color: "#ffffff",
|
|
21056
|
+
depthTest: false,
|
|
21057
|
+
depthWrite: false,
|
|
21058
|
+
side: import_three42.DoubleSide,
|
|
21059
|
+
toneMapped: false,
|
|
21060
|
+
transparent: true
|
|
21061
|
+
}
|
|
21062
|
+
)
|
|
20909
21063
|
}
|
|
20910
21064
|
)
|
|
20911
21065
|
]
|
|
@@ -20937,7 +21091,7 @@ void main() {
|
|
|
20937
21091
|
// src/webvr/stereo.tsx
|
|
20938
21092
|
var import_fiber32 = require("@react-three/fiber");
|
|
20939
21093
|
var import_react66 = require("react");
|
|
20940
|
-
var
|
|
21094
|
+
var import_three43 = require("three");
|
|
20941
21095
|
|
|
20942
21096
|
// src/webvr/lens-center.ts
|
|
20943
21097
|
function physicalScreenFromDiagonal(screensizeInches, displayAspect) {
|
|
@@ -21028,7 +21182,7 @@ function computeStereoLayout(logicalWidth, logicalHeight, pixelRatio, oversampli
|
|
|
21028
21182
|
}
|
|
21029
21183
|
|
|
21030
21184
|
// src/webvr/stereo.tsx
|
|
21031
|
-
var TOE_IN = new
|
|
21185
|
+
var TOE_IN = new import_three43.Matrix4();
|
|
21032
21186
|
var vertexShader = `
|
|
21033
21187
|
varying vec2 vUv;
|
|
21034
21188
|
void main() {
|
|
@@ -21052,38 +21206,38 @@ void main() {
|
|
|
21052
21206
|
}
|
|
21053
21207
|
`;
|
|
21054
21208
|
function createDistortionResources() {
|
|
21055
|
-
const target = new
|
|
21209
|
+
const target = new import_three43.WebGLRenderTarget(1, 1, {
|
|
21056
21210
|
depthBuffer: true,
|
|
21057
21211
|
stencilBuffer: false
|
|
21058
21212
|
});
|
|
21059
|
-
const geometry = new
|
|
21060
|
-
const material = new
|
|
21213
|
+
const geometry = new import_three43.PlaneGeometry(2, 2);
|
|
21214
|
+
const material = new import_three43.ShaderMaterial({
|
|
21061
21215
|
depthTest: false,
|
|
21062
21216
|
depthWrite: false,
|
|
21063
21217
|
fragmentShader,
|
|
21064
21218
|
uniforms: {
|
|
21065
|
-
distortion: { value: new
|
|
21066
|
-
lensCenter: { value: new
|
|
21219
|
+
distortion: { value: new import_three43.Vector2() },
|
|
21220
|
+
lensCenter: { value: new import_three43.Vector2() },
|
|
21067
21221
|
sourceTexture: { value: target.texture }
|
|
21068
21222
|
},
|
|
21069
21223
|
vertexShader
|
|
21070
21224
|
});
|
|
21071
|
-
const mesh = new
|
|
21072
|
-
const scene = new
|
|
21225
|
+
const mesh = new import_three43.Mesh(geometry, material);
|
|
21226
|
+
const scene = new import_three43.Scene();
|
|
21073
21227
|
scene.add(mesh);
|
|
21074
|
-
const maskMaterial = new
|
|
21228
|
+
const maskMaterial = new import_three43.ShaderMaterial({
|
|
21075
21229
|
vertexShader,
|
|
21076
21230
|
fragmentShader: stereoLensMaskFragmentShader,
|
|
21077
21231
|
uniforms: material.uniforms,
|
|
21078
21232
|
depthTest: false,
|
|
21079
21233
|
depthWrite: false
|
|
21080
21234
|
});
|
|
21081
|
-
const maskScene = new
|
|
21082
|
-
maskScene.add(new
|
|
21235
|
+
const maskScene = new import_three43.Scene();
|
|
21236
|
+
maskScene.add(new import_three43.Mesh(geometry, maskMaterial));
|
|
21083
21237
|
return {
|
|
21084
21238
|
maskScene,
|
|
21085
21239
|
maskMaterial,
|
|
21086
|
-
camera: new
|
|
21240
|
+
camera: new import_three43.OrthographicCamera(-1, 1, 1, -1, 0, 1),
|
|
21087
21241
|
geometry,
|
|
21088
21242
|
material,
|
|
21089
21243
|
mesh,
|
|
@@ -21144,15 +21298,15 @@ function WebVRStereoRenderer({
|
|
|
21144
21298
|
const runtime = (0, import_react66.useContext)(WebVRRuntimeContext);
|
|
21145
21299
|
const fallbackStereoRef = (0, import_react66.useRef)(null);
|
|
21146
21300
|
if (!fallbackStereoRef.current) {
|
|
21147
|
-
fallbackStereoRef.current = new
|
|
21301
|
+
fallbackStereoRef.current = new import_three43.StereoCamera();
|
|
21148
21302
|
}
|
|
21149
21303
|
const stereo = runtime?.stereoView.stereo ?? fallbackStereoRef.current;
|
|
21150
21304
|
const stereoRef = (0, import_react66.useRef)(stereo);
|
|
21151
21305
|
stereoRef.current = stereo;
|
|
21152
21306
|
const resources = (0, import_react66.useMemo)(createDistortionResources, []);
|
|
21153
|
-
const sizeRef = (0, import_react66.useRef)(new
|
|
21154
|
-
const viewportRef = (0, import_react66.useRef)(new
|
|
21155
|
-
const scissorRef = (0, import_react66.useRef)(new
|
|
21307
|
+
const sizeRef = (0, import_react66.useRef)(new import_three43.Vector2());
|
|
21308
|
+
const viewportRef = (0, import_react66.useRef)(new import_three43.Vector4());
|
|
21309
|
+
const scissorRef = (0, import_react66.useRef)(new import_three43.Vector4());
|
|
21156
21310
|
const originalFovRef = (0, import_react66.useRef)(null);
|
|
21157
21311
|
const stereoActiveRef = (0, import_react66.useRef)(false);
|
|
21158
21312
|
const profileRef = (0, import_react66.useRef)(profile);
|
|
@@ -21173,7 +21327,7 @@ function WebVRStereoRenderer({
|
|
|
21173
21327
|
(0, import_react66.useEffect)(() => {
|
|
21174
21328
|
const originalRender = gl.render.bind(gl);
|
|
21175
21329
|
gl.render = (sceneToRender, cameraToRender) => {
|
|
21176
|
-
if (!stereoActiveRef.current || !(cameraToRender instanceof
|
|
21330
|
+
if (!stereoActiveRef.current || !(cameraToRender instanceof import_three43.PerspectiveCamera)) {
|
|
21177
21331
|
originalRender(sceneToRender, cameraToRender);
|
|
21178
21332
|
return;
|
|
21179
21333
|
}
|
|
@@ -21255,7 +21409,7 @@ function WebVRStereoRenderer({
|
|
|
21255
21409
|
if (runtime) {
|
|
21256
21410
|
runtime.stereoView.active = fallback;
|
|
21257
21411
|
}
|
|
21258
|
-
if (fallback && camera instanceof
|
|
21412
|
+
if (fallback && camera instanceof import_three43.PerspectiveCamera) {
|
|
21259
21413
|
syncStereoCameras(
|
|
21260
21414
|
stereoRef.current,
|
|
21261
21415
|
camera,
|
|
@@ -21267,7 +21421,7 @@ function WebVRStereoRenderer({
|
|
|
21267
21421
|
);
|
|
21268
21422
|
return;
|
|
21269
21423
|
}
|
|
21270
|
-
if (originalFovRef.current !== null && camera instanceof
|
|
21424
|
+
if (originalFovRef.current !== null && camera instanceof import_three43.PerspectiveCamera) {
|
|
21271
21425
|
camera.fov = originalFovRef.current;
|
|
21272
21426
|
camera.updateProjectionMatrix();
|
|
21273
21427
|
originalFovRef.current = null;
|
|
@@ -23042,7 +23196,7 @@ function usePanoViewer() {
|
|
|
23042
23196
|
// src/video/pano-video.tsx
|
|
23043
23197
|
var import_fiber34 = require("@react-three/fiber");
|
|
23044
23198
|
var import_react72 = require("react");
|
|
23045
|
-
var
|
|
23199
|
+
var import_three44 = require("three");
|
|
23046
23200
|
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
23047
23201
|
var EMPTY_TRACKS = [];
|
|
23048
23202
|
var EMPTY_RATES = DEFAULT_PANO_VIDEO_PLAYBACK_RATES;
|
|
@@ -23119,8 +23273,8 @@ function findTextTrack(video, tracks, trackId) {
|
|
|
23119
23273
|
return list.length > 0 ? list[0] : null;
|
|
23120
23274
|
}
|
|
23121
23275
|
function applyEquirectangularLayout(texture, anisotropy) {
|
|
23122
|
-
texture.colorSpace =
|
|
23123
|
-
texture.wrapS =
|
|
23276
|
+
texture.colorSpace = import_three44.SRGBColorSpace;
|
|
23277
|
+
texture.wrapS = import_three44.RepeatWrapping;
|
|
23124
23278
|
texture.repeat.x = -1;
|
|
23125
23279
|
texture.offset.x = 1;
|
|
23126
23280
|
texture.anisotropy = anisotropy;
|
|
@@ -23139,7 +23293,7 @@ function usePosterTexture2(poster, onError) {
|
|
|
23139
23293
|
active = false;
|
|
23140
23294
|
};
|
|
23141
23295
|
}
|
|
23142
|
-
const loader = new
|
|
23296
|
+
const loader = new import_three44.TextureLoader();
|
|
23143
23297
|
loader.load(
|
|
23144
23298
|
poster,
|
|
23145
23299
|
(loadedTexture) => {
|
|
@@ -23151,9 +23305,9 @@ function usePosterTexture2(poster, onError) {
|
|
|
23151
23305
|
loadedTexture,
|
|
23152
23306
|
gl.capabilities.getMaxAnisotropy()
|
|
23153
23307
|
);
|
|
23154
|
-
loadedTexture.wrapT =
|
|
23155
|
-
loadedTexture.magFilter =
|
|
23156
|
-
loadedTexture.minFilter =
|
|
23308
|
+
loadedTexture.wrapT = import_three44.RepeatWrapping;
|
|
23309
|
+
loadedTexture.magFilter = import_three44.LinearFilter;
|
|
23310
|
+
loadedTexture.minFilter = import_three44.LinearMipmapLinearFilter;
|
|
23157
23311
|
loadedTexture.generateMipmaps = true;
|
|
23158
23312
|
setTexture(loadedTexture);
|
|
23159
23313
|
},
|
|
@@ -23307,10 +23461,10 @@ function PanoVideo({
|
|
|
23307
23461
|
video.muted = true;
|
|
23308
23462
|
applyInlineVideoPlayback(video, true);
|
|
23309
23463
|
video.preload = "metadata";
|
|
23310
|
-
const texture = new
|
|
23464
|
+
const texture = new import_three44.VideoTexture(video);
|
|
23311
23465
|
applyEquirectangularLayout(texture, 1);
|
|
23312
|
-
texture.magFilter =
|
|
23313
|
-
texture.minFilter =
|
|
23466
|
+
texture.magFilter = import_three44.LinearFilter;
|
|
23467
|
+
texture.minFilter = import_three44.LinearFilter;
|
|
23314
23468
|
texture.generateMipmaps = false;
|
|
23315
23469
|
return { video, texture };
|
|
23316
23470
|
}, []);
|
|
@@ -23371,6 +23525,7 @@ function PanoVideo({
|
|
|
23371
23525
|
ended: playbackState === "ended",
|
|
23372
23526
|
currentTime: video?.currentTime ?? 0,
|
|
23373
23527
|
duration: video && Number.isFinite(video.duration) ? video.duration : 0,
|
|
23528
|
+
hasAudio: video ? probeMediaHasAudio(video) : void 0,
|
|
23374
23529
|
volume: video ? clampVolume(video.volume) : clampVolume(volume),
|
|
23375
23530
|
volumeAdjustable: mediaCapabilitiesRef.current.volumeAdjustable,
|
|
23376
23531
|
muted: video?.muted ?? muted,
|
|
@@ -23572,7 +23727,7 @@ function PanoVideo({
|
|
|
23572
23727
|
emitSnapshot();
|
|
23573
23728
|
},
|
|
23574
23729
|
setVolume: (nextVolume) => {
|
|
23575
|
-
if (!mediaCapabilitiesRef.current.volumeAdjustable) {
|
|
23730
|
+
if (!Number.isFinite(nextVolume) || !mediaCapabilitiesRef.current.volumeAdjustable) {
|
|
23576
23731
|
return;
|
|
23577
23732
|
}
|
|
23578
23733
|
video.volume = clampVolume(nextVolume);
|
|
@@ -23676,7 +23831,7 @@ function PanoVideo({
|
|
|
23676
23831
|
const handleVolume = () => {
|
|
23677
23832
|
emitSnapshot();
|
|
23678
23833
|
};
|
|
23679
|
-
video
|
|
23834
|
+
const unsubscribeAudio = subscribeMediaAudio(video, handleTimeUpdate);
|
|
23680
23835
|
video.addEventListener("durationchange", handleTimeUpdate);
|
|
23681
23836
|
video.addEventListener("progress", handleTimeUpdate);
|
|
23682
23837
|
video.addEventListener("play", handlePlay);
|
|
@@ -23686,7 +23841,7 @@ function PanoVideo({
|
|
|
23686
23841
|
video.addEventListener("ratechange", handleVolume);
|
|
23687
23842
|
return () => {
|
|
23688
23843
|
active = false;
|
|
23689
|
-
|
|
23844
|
+
unsubscribeAudio();
|
|
23690
23845
|
video.removeEventListener("durationchange", handleTimeUpdate);
|
|
23691
23846
|
video.removeEventListener("progress", handleTimeUpdate);
|
|
23692
23847
|
video.removeEventListener("play", handlePlay);
|
|
@@ -23746,7 +23901,7 @@ function PanoVideo({
|
|
|
23746
23901
|
activeTexture ? /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(
|
|
23747
23902
|
"mesh",
|
|
23748
23903
|
{
|
|
23749
|
-
rotation: [0,
|
|
23904
|
+
rotation: [0, import_three44.MathUtils.degToRad(90 + yawOffset2), 0],
|
|
23750
23905
|
visible,
|
|
23751
23906
|
children: [
|
|
23752
23907
|
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("sphereGeometry", { args: [DEFAULT_PANORAMA_RADIUS, 128, 64] }),
|
|
@@ -23754,7 +23909,7 @@ function PanoVideo({
|
|
|
23754
23909
|
PanoBasicMaterial,
|
|
23755
23910
|
{
|
|
23756
23911
|
map: activeTexture,
|
|
23757
|
-
side:
|
|
23912
|
+
side: import_three44.BackSide,
|
|
23758
23913
|
toneMapped: false
|
|
23759
23914
|
}
|
|
23760
23915
|
)
|
|
@@ -24965,7 +25120,7 @@ function PanoMapOverlay({
|
|
|
24965
25120
|
var import_react76 = require("react");
|
|
24966
25121
|
var import_client2 = require("react-dom/client");
|
|
24967
25122
|
var import_fiber35 = require("@react-three/fiber");
|
|
24968
|
-
var
|
|
25123
|
+
var import_three45 = require("three");
|
|
24969
25124
|
|
|
24970
25125
|
// src/webvr/scene-menu-layout.ts
|
|
24971
25126
|
var bounded = (value, fallback, min, max) => Number.isFinite(value) ? Math.min(max, Math.max(min, value)) : fallback;
|
|
@@ -25175,7 +25330,7 @@ function MenuSurface({
|
|
|
25175
25330
|
timer: 0
|
|
25176
25331
|
});
|
|
25177
25332
|
const group = (0, import_react76.useRef)(null);
|
|
25178
|
-
const direction = (0, import_react76.useMemo)(() => new
|
|
25333
|
+
const direction = (0, import_react76.useMemo)(() => new import_three45.Vector3(), []);
|
|
25179
25334
|
const [reduced, setReduced] = (0, import_react76.useState)(false);
|
|
25180
25335
|
(0, import_react76.useEffect)(() => {
|
|
25181
25336
|
const media = matchMedia("(prefers-reduced-motion: reduce)");
|
|
@@ -25231,13 +25386,13 @@ function MenuSurface({
|
|
|
25231
25386
|
const canvas = document.createElement("canvas");
|
|
25232
25387
|
canvas.width = w * MENU_TEXTURE_SCALE;
|
|
25233
25388
|
canvas.height = atlasHeight * MENU_TEXTURE_SCALE;
|
|
25234
|
-
const texture = new
|
|
25235
|
-
texture.colorSpace =
|
|
25236
|
-
texture.minFilter =
|
|
25237
|
-
texture.magFilter =
|
|
25389
|
+
const texture = new import_three45.CanvasTexture(canvas);
|
|
25390
|
+
texture.colorSpace = import_three45.SRGBColorSpace;
|
|
25391
|
+
texture.minFilter = import_three45.LinearMipmapLinearFilter;
|
|
25392
|
+
texture.magFilter = import_three45.LinearFilter;
|
|
25238
25393
|
texture.generateMipmaps = true;
|
|
25239
25394
|
texture.anisotropy = Math.min(4, gl.capabilities.getMaxAnisotropy());
|
|
25240
|
-
const material = new
|
|
25395
|
+
const material = new import_three45.MeshBasicMaterial({
|
|
25241
25396
|
map: texture,
|
|
25242
25397
|
transparent: true,
|
|
25243
25398
|
depthTest: false,
|
|
@@ -25308,12 +25463,12 @@ function MenuSurface({
|
|
|
25308
25463
|
}
|
|
25309
25464
|
}
|
|
25310
25465
|
}
|
|
25311
|
-
const geometry = new
|
|
25466
|
+
const geometry = new import_three45.BufferGeometry();
|
|
25312
25467
|
geometry.setAttribute(
|
|
25313
25468
|
"position",
|
|
25314
|
-
new
|
|
25469
|
+
new import_three45.Float32BufferAttribute(positions, 3)
|
|
25315
25470
|
);
|
|
25316
|
-
geometry.setAttribute("uv", new
|
|
25471
|
+
geometry.setAttribute("uv", new import_three45.Float32BufferAttribute(uvs, 2));
|
|
25317
25472
|
geometry.computeVertexNormals();
|
|
25318
25473
|
result.push({
|
|
25319
25474
|
canvas,
|
|
@@ -25340,7 +25495,7 @@ function MenuSurface({
|
|
|
25340
25495
|
);
|
|
25341
25496
|
const blocker = (0, import_react76.useMemo)(() => {
|
|
25342
25497
|
if (!open || layout !== "arc") return null;
|
|
25343
|
-
const geometry = new
|
|
25498
|
+
const geometry = new import_three45.PlaneGeometry(1, 1, Math.ceil(degrees / 3), 1);
|
|
25344
25499
|
const positions = geometry.attributes.position;
|
|
25345
25500
|
const top = sceneMenuPoint(
|
|
25346
25501
|
0,
|
|
@@ -25893,7 +26048,7 @@ function MenuSurface({
|
|
|
25893
26048
|
},
|
|
25894
26049
|
raycast: function(raycaster, intersections) {
|
|
25895
26050
|
if (!state.current.closing && state.current.alpha > 0)
|
|
25896
|
-
|
|
26051
|
+
import_three45.Mesh.prototype.raycast.call(this, raycaster, intersections);
|
|
25897
26052
|
}
|
|
25898
26053
|
},
|
|
25899
26054
|
index
|