fix(web): integrate zoom toggle button into panorama photo viewer (#24189)
parent
c0a3b58bba
commit
e36261b552
|
|
@ -512,7 +512,7 @@
|
||||||
{:else if asset.exifInfo?.projectionType === ProjectionType.EQUIRECTANGULAR || (asset.originalPath && asset.originalPath
|
{:else if asset.exifInfo?.projectionType === ProjectionType.EQUIRECTANGULAR || (asset.originalPath && asset.originalPath
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.endsWith('.insp'))}
|
.endsWith('.insp'))}
|
||||||
<ImagePanoramaViewer {asset} />
|
<ImagePanoramaViewer bind:zoomToggle {asset} />
|
||||||
{:else if isShowEditor && selectedEditType === 'crop'}
|
{:else if isShowEditor && selectedEditType === 'crop'}
|
||||||
<CropArea {asset} />
|
<CropArea {asset} />
|
||||||
{:else}
|
{:else}
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,12 @@
|
||||||
import { t } from 'svelte-i18n';
|
import { t } from 'svelte-i18n';
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
|
|
||||||
interface Props {
|
type Props = {
|
||||||
asset: AssetResponseDto;
|
asset: AssetResponseDto;
|
||||||
}
|
zoomToggle?: (() => void) | null;
|
||||||
|
};
|
||||||
|
|
||||||
const { asset }: Props = $props();
|
let { asset, zoomToggle = $bindable() }: Props = $props();
|
||||||
|
|
||||||
const loadAssetData = async (id: string) => {
|
const loadAssetData = async (id: string) => {
|
||||||
const data = await viewAsset({ ...authManager.params, id, size: AssetMediaSize.Preview });
|
const data = await viewAsset({ ...authManager.params, id, size: AssetMediaSize.Preview });
|
||||||
|
|
@ -24,6 +25,7 @@
|
||||||
<LoadingSpinner />
|
<LoadingSpinner />
|
||||||
{:then [data, { default: PhotoSphereViewer }]}
|
{:then [data, { default: PhotoSphereViewer }]}
|
||||||
<PhotoSphereViewer
|
<PhotoSphereViewer
|
||||||
|
bind:zoomToggle
|
||||||
panorama={data}
|
panorama={data}
|
||||||
originalPanorama={isWebCompatibleImage(asset)
|
originalPanorama={isWebCompatibleImage(asset)
|
||||||
? getAssetOriginalUrl(asset.id)
|
? getAssetOriginalUrl(asset.id)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { shortcuts } from '$lib/actions/shortcut';
|
||||||
import { boundingBoxesArray, type Faces } from '$lib/stores/people.store';
|
import { boundingBoxesArray, type Faces } from '$lib/stores/people.store';
|
||||||
import { alwaysLoadOriginalFile } from '$lib/stores/preferences.store';
|
import { alwaysLoadOriginalFile } from '$lib/stores/preferences.store';
|
||||||
|
import { photoZoomState } from '$lib/stores/zoom-image.store';
|
||||||
import {
|
import {
|
||||||
EquirectangularAdapter,
|
EquirectangularAdapter,
|
||||||
Viewer,
|
Viewer,
|
||||||
|
|
@ -24,15 +26,23 @@
|
||||||
strokeLinejoin: 'round',
|
strokeLinejoin: 'round',
|
||||||
};
|
};
|
||||||
|
|
||||||
interface Props {
|
type Props = {
|
||||||
panorama: string | { source: string };
|
panorama: string | { source: string };
|
||||||
originalPanorama?: string | { source: 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;
|
||||||
}
|
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 container: HTMLDivElement | undefined = $state();
|
||||||
let viewer: Viewer;
|
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(() => {
|
onMount(() => {
|
||||||
if (!container) {
|
if (!container) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -139,10 +157,15 @@
|
||||||
const resolutionPlugin = viewer.getPlugin<ResolutionPlugin>(ResolutionPlugin);
|
const resolutionPlugin = viewer.getPlugin<ResolutionPlugin>(ResolutionPlugin);
|
||||||
const zoomHandler = ({ zoomLevel }: events.ZoomUpdatedEvent) => {
|
const zoomHandler = ({ zoomLevel }: events.ZoomUpdatedEvent) => {
|
||||||
// zoomLevel range: [0, 100]
|
// 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
|
// Replace the preview with the original
|
||||||
void resolutionPlugin.setResolution('original');
|
void resolutionPlugin.setResolution('original');
|
||||||
viewer.removeEventListener(events.ZoomUpdatedEvent.type, zoomHandler);
|
hasChangedResolution = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -158,7 +181,13 @@
|
||||||
viewer.destroy();
|
viewer.destroy();
|
||||||
}
|
}
|
||||||
boundingBoxesUnsubscribe();
|
boundingBoxesUnsubscribe();
|
||||||
|
// zoomHandler is not called on initial load. Viewer initial zoom is 1, but photoZoomState could be != 1.
|
||||||
|
photoZoomState.set({
|
||||||
|
...$photoZoomState,
|
||||||
|
currentZoom: 1,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<svelte:document use:shortcuts={[{ shortcut: { key: 'z' }, onShortcut: zoomToggle, preventDefault: true }]} />
|
||||||
<div class="h-full w-full mb-0" bind:this={container}></div>
|
<div class="h-full w-full mb-0" bind:this={container}></div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue