diff --git a/web/src/lib/components/asset-viewer/asset-viewer.svelte b/web/src/lib/components/asset-viewer/asset-viewer.svelte index 7570278e51..b657f34ece 100644 --- a/web/src/lib/components/asset-viewer/asset-viewer.svelte +++ b/web/src/lib/components/asset-viewer/asset-viewer.svelte @@ -512,7 +512,7 @@ {:else if asset.exifInfo?.projectionType === ProjectionType.EQUIRECTANGULAR || (asset.originalPath && asset.originalPath .toLowerCase() .endsWith('.insp'))} - + {:else if isShowEditor && selectedEditType === 'crop'} {:else} diff --git a/web/src/lib/components/asset-viewer/image-panorama-viewer.svelte b/web/src/lib/components/asset-viewer/image-panorama-viewer.svelte index 7334aab4d4..08ba43526d 100644 --- a/web/src/lib/components/asset-viewer/image-panorama-viewer.svelte +++ b/web/src/lib/components/asset-viewer/image-panorama-viewer.svelte @@ -7,11 +7,12 @@ import { t } from 'svelte-i18n'; import { fade } from 'svelte/transition'; - interface Props { + type Props = { asset: AssetResponseDto; - } + zoomToggle?: (() => void) | null; + }; - const { asset }: Props = $props(); + let { asset, zoomToggle = $bindable() }: Props = $props(); const loadAssetData = async (id: string) => { const data = await viewAsset({ ...authManager.params, id, size: AssetMediaSize.Preview }); @@ -24,6 +25,7 @@ {:then [data, { default: PhotoSphereViewer }]} + import { shortcuts } from '$lib/actions/shortcut'; import { boundingBoxesArray, type Faces } from '$lib/stores/people.store'; import { alwaysLoadOriginalFile } from '$lib/stores/preferences.store'; + import { photoZoomState } from '$lib/stores/zoom-image.store'; import { EquirectangularAdapter, Viewer, @@ -24,15 +26,23 @@ strokeLinejoin: 'round', }; - interface Props { + type Props = { panorama: string | { source: string }; originalPanorama?: string | { source: string }; adapter?: AdapterConstructor | [AdapterConstructor, unknown]; plugins?: (PluginConstructor | [PluginConstructor, unknown])[]; navbar?: boolean; - } + zoomToggle?: (() => void) | null; + }; - let { panorama, originalPanorama, adapter = EquirectangularAdapter, plugins = [], navbar = false }: Props = $props(); + let { + panorama, + originalPanorama, + adapter = EquirectangularAdapter, + plugins = [], + navbar = false, + zoomToggle = $bindable(), + }: Props = $props(); let container: HTMLDivElement | undefined = $state(); let viewer: Viewer; @@ -93,6 +103,14 @@ } }); + zoomToggle = () => { + if (!viewer) { + return; + } + viewer.animate({ zoom: $photoZoomState.currentZoom > 1 ? 50 : 83.3, speed: 250 }); + }; + + let hasChangedResolution: boolean = false; onMount(() => { if (!container) { return; @@ -139,10 +157,15 @@ const resolutionPlugin = viewer.getPlugin(ResolutionPlugin); const zoomHandler = ({ zoomLevel }: events.ZoomUpdatedEvent) => { // zoomLevel range: [0, 100] - if (Math.round(zoomLevel) >= 75) { + photoZoomState.set({ + ...$photoZoomState, + currentZoom: zoomLevel / 50, + }); + + if (Math.round(zoomLevel) >= 75 && !hasChangedResolution) { // Replace the preview with the original void resolutionPlugin.setResolution('original'); - viewer.removeEventListener(events.ZoomUpdatedEvent.type, zoomHandler); + hasChangedResolution = true; } }; @@ -158,7 +181,13 @@ viewer.destroy(); } boundingBoxesUnsubscribe(); + // zoomHandler is not called on initial load. Viewer initial zoom is 1, but photoZoomState could be != 1. + photoZoomState.set({ + ...$photoZoomState, + currentZoom: 1, + }); }); +