feat: resolution selection and default preview playback for 360° panorama videos (#15747)

* original/preview switching in photo-sphere-viewer

1. default to preview in photo-sphere-viewer video mode
2. install and integrate @photo-sphere-viewer/settings-plugin & @photo-sphere-viewer/resolution-plugin

* fix lint errors
This commit is contained in:
PastLeo 2025-01-28 23:09:40 +08:00 committed by GitHub
parent 92dff839d0
commit 08db77db23
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 66 additions and 11 deletions

21
web/package-lock.json generated
View File

@ -16,6 +16,8 @@
"@mdi/js": "^7.4.47", "@mdi/js": "^7.4.47",
"@photo-sphere-viewer/core": "^5.11.5", "@photo-sphere-viewer/core": "^5.11.5",
"@photo-sphere-viewer/equirectangular-video-adapter": "^5.11.5", "@photo-sphere-viewer/equirectangular-video-adapter": "^5.11.5",
"@photo-sphere-viewer/resolution-plugin": "^5.11.5",
"@photo-sphere-viewer/settings-plugin": "^5.11.5",
"@photo-sphere-viewer/video-plugin": "^5.11.5", "@photo-sphere-viewer/video-plugin": "^5.11.5",
"@zoom-image/svelte": "^0.3.0", "@zoom-image/svelte": "^0.3.0",
"dom-to-image": "^2.6.0", "dom-to-image": "^2.6.0",
@ -1669,6 +1671,25 @@
"@photo-sphere-viewer/video-plugin": "5.11.5" "@photo-sphere-viewer/video-plugin": "5.11.5"
} }
}, },
"node_modules/@photo-sphere-viewer/resolution-plugin": {
"version": "5.11.5",
"resolved": "https://registry.npmjs.org/@photo-sphere-viewer/resolution-plugin/-/resolution-plugin-5.11.5.tgz",
"integrity": "sha512-Dbvp5bBtozD3IWt1Q0wORVaZBcB1bV9xUeoOS9A7F7b3EkQ2pkC5/jot/1AyM4wtU5wJ63NWHskQ1d7m6WWazQ==",
"license": "MIT",
"peerDependencies": {
"@photo-sphere-viewer/core": "5.11.5",
"@photo-sphere-viewer/settings-plugin": "5.11.5"
}
},
"node_modules/@photo-sphere-viewer/settings-plugin": {
"version": "5.11.5",
"resolved": "https://registry.npmjs.org/@photo-sphere-viewer/settings-plugin/-/settings-plugin-5.11.5.tgz",
"integrity": "sha512-ZgYaWjiBMhsoRH5ddW3h+v4J4LPmofsT7BBRq5UCssWw2Fsrvv7mFFRi4UbZ1qzeKmvNUOr8BaFQgX1ZLvUWfQ==",
"license": "MIT",
"peerDependencies": {
"@photo-sphere-viewer/core": "5.11.5"
}
},
"node_modules/@photo-sphere-viewer/video-plugin": { "node_modules/@photo-sphere-viewer/video-plugin": {
"version": "5.11.5", "version": "5.11.5",
"resolved": "https://registry.npmjs.org/@photo-sphere-viewer/video-plugin/-/video-plugin-5.11.5.tgz", "resolved": "https://registry.npmjs.org/@photo-sphere-viewer/video-plugin/-/video-plugin-5.11.5.tgz",

View File

@ -72,6 +72,8 @@
"@mdi/js": "^7.4.47", "@mdi/js": "^7.4.47",
"@photo-sphere-viewer/core": "^5.11.5", "@photo-sphere-viewer/core": "^5.11.5",
"@photo-sphere-viewer/equirectangular-video-adapter": "^5.11.5", "@photo-sphere-viewer/equirectangular-video-adapter": "^5.11.5",
"@photo-sphere-viewer/resolution-plugin": "^5.11.5",
"@photo-sphere-viewer/settings-plugin": "^5.11.5",
"@photo-sphere-viewer/video-plugin": "^5.11.5", "@photo-sphere-viewer/video-plugin": "^5.11.5",
"@zoom-image/svelte": "^0.3.0", "@zoom-image/svelte": "^0.3.0",
"dom-to-image": "^2.6.0", "dom-to-image": "^2.6.0",

View File

@ -24,7 +24,7 @@
{:then [data, { default: PhotoSphereViewer }]} {:then [data, { default: PhotoSphereViewer }]}
<PhotoSphereViewer <PhotoSphereViewer
panorama={data} panorama={data}
originalImageUrl={isWebCompatibleImage(asset) ? getAssetOriginalUrl(asset.id) : undefined} originalPanorama={isWebCompatibleImage(asset) ? getAssetOriginalUrl(asset.id) : undefined}
/> />
{:catch} {:catch}
{$t('errors.failed_to_load_asset')} {$t('errors.failed_to_load_asset')}

View File

@ -7,18 +7,21 @@
type AdapterConstructor, type AdapterConstructor,
type PluginConstructor, type PluginConstructor,
} from '@photo-sphere-viewer/core'; } from '@photo-sphere-viewer/core';
import { SettingsPlugin } from '@photo-sphere-viewer/settings-plugin';
import { ResolutionPlugin } from '@photo-sphere-viewer/resolution-plugin';
import '@photo-sphere-viewer/core/index.css'; import '@photo-sphere-viewer/core/index.css';
import '@photo-sphere-viewer/settings-plugin/index.css';
import { onDestroy, onMount } from 'svelte'; import { onDestroy, onMount } from 'svelte';
interface Props { interface Props {
panorama: string | { source: string }; panorama: string | { source: string };
originalImageUrl?: string; originalPanorama?: string | { source: string };
adapter?: AdapterConstructor | [AdapterConstructor, unknown]; adapter?: AdapterConstructor | [AdapterConstructor, unknown];
plugins?: (PluginConstructor | [PluginConstructor, unknown])[]; plugins?: (PluginConstructor | [PluginConstructor, unknown])[];
navbar?: boolean; navbar?: boolean;
} }
let { panorama, originalImageUrl, adapter = EquirectangularAdapter, plugins = [], navbar = false }: Props = $props(); let { panorama, originalPanorama, adapter = EquirectangularAdapter, plugins = [], navbar = false }: Props = $props();
let container: HTMLDivElement | undefined = $state(); let container: HTMLDivElement | undefined = $state();
let viewer: Viewer; let viewer: Viewer;
@ -30,9 +33,33 @@
viewer = new Viewer({ viewer = new Viewer({
adapter, adapter,
plugins, plugins: [
SettingsPlugin,
[
ResolutionPlugin,
{
defaultResolution: $alwaysLoadOriginalFile && originalPanorama ? 'original' : 'default',
resolutions: [
{
id: 'default',
label: 'Default',
panorama,
},
...(originalPanorama
? [
{
id: 'original',
label: 'Original',
panorama: originalPanorama,
},
]
: []),
],
},
],
...plugins,
],
container, container,
panorama,
touchmoveTwoFingers: false, touchmoveTwoFingers: false,
mousewheelCtrlKey: false, mousewheelCtrlKey: false,
navbar, navbar,
@ -40,15 +67,14 @@
maxFov: 120, maxFov: 120,
fisheye: false, fisheye: false,
}); });
const resolutionPlugin = viewer.getPlugin(ResolutionPlugin) as ResolutionPlugin;
if (originalImageUrl && !$alwaysLoadOriginalFile) { if (originalPanorama && !$alwaysLoadOriginalFile) {
const zoomHandler = ({ zoomLevel }: events.ZoomUpdatedEvent) => { const zoomHandler = ({ zoomLevel }: events.ZoomUpdatedEvent) => {
// zoomLevel range: [0, 100] // zoomLevel range: [0, 100]
if (Math.round(zoomLevel) >= 75) { if (Math.round(zoomLevel) >= 75) {
// Replace the preview with the original // Replace the preview with the original
viewer.setPanorama(originalImageUrl, { showLoader: false, speed: 150 }).catch(() => { void resolutionPlugin.setResolution('original');
viewer.setPanorama(panorama, { showLoader: false, speed: 0 }).catch(() => {});
});
viewer.removeEventListener(events.ZoomUpdatedEvent.type, zoomHandler); viewer.removeEventListener(events.ZoomUpdatedEvent.type, zoomHandler);
} }
}; };

View File

@ -1,5 +1,5 @@
<script lang="ts"> <script lang="ts">
import { getAssetOriginalUrl } from '$lib/utils'; import { getAssetPlaybackUrl, getAssetOriginalUrl } from '$lib/utils';
import { fade } from 'svelte/transition'; import { fade } from 'svelte/transition';
import LoadingSpinner from '../shared-components/loading-spinner.svelte'; import LoadingSpinner from '../shared-components/loading-spinner.svelte';
import { t } from 'svelte-i18n'; import { t } from 'svelte-i18n';
@ -22,7 +22,13 @@
{#await modules} {#await modules}
<LoadingSpinner /> <LoadingSpinner />
{:then [PhotoSphereViewer, adapter, videoPlugin]} {:then [PhotoSphereViewer, adapter, videoPlugin]}
<PhotoSphereViewer panorama={{ source: getAssetOriginalUrl(assetId) }} plugins={[videoPlugin]} {adapter} navbar /> <PhotoSphereViewer
panorama={{ source: getAssetPlaybackUrl(assetId) }}
originalPanorama={{ source: getAssetOriginalUrl(assetId) }}
plugins={[videoPlugin]}
{adapter}
navbar
/>
{:catch} {:catch}
{$t('errors.failed_to_load_asset')} {$t('errors.failed_to_load_asset')}
{/await} {/await}