Skip to content

Commit 862d6d9

Browse files
authored
feat(web): load original panorama image when zoomed in to 75% or above (#12222)
* feat(web): load original panorama image when zoomed in to 75% or above * add checks that original 360 image is web compatible and better error handling * fix web compatability check typing * fix asset type
1 parent bd6c5e1 commit 862d6d9

File tree

2 files changed

+29
-2
lines changed

2 files changed

+29
-2
lines changed

Diff for: web/src/lib/components/asset-viewer/panorama-viewer.svelte

+13-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
<script lang="ts">
22
import { getAssetOriginalUrl, getKey } from '$lib/utils';
3+
import { isWebCompatibleImage } from '$lib/utils/asset-utils';
34
import { AssetMediaSize, AssetTypeEnum, viewAsset, type AssetResponseDto } from '@immich/sdk';
45
import type { AdapterConstructor, PluginConstructor } from '@photo-sphere-viewer/core';
56
import { fade } from 'svelte/transition';
67
import LoadingSpinner from '../shared-components/loading-spinner.svelte';
78
import { t } from 'svelte-i18n';
8-
export let asset: Pick<AssetResponseDto, 'id' | 'type'>;
9+
export let asset: { id: string; type: AssetTypeEnum.Video } | AssetResponseDto;
910
1011
const photoSphereConfigs =
1112
asset.type === AssetTypeEnum.Video
@@ -27,14 +28,24 @@
2728
const url = URL.createObjectURL(data);
2829
return url;
2930
};
31+
32+
const originalImageUrl =
33+
asset.type === AssetTypeEnum.Image && isWebCompatibleImage(asset) ? getAssetOriginalUrl(asset.id) : null;
3034
</script>
3135

3236
<div transition:fade={{ duration: 150 }} class="flex h-full select-none place-content-center place-items-center">
3337
<!-- the photo sphere viewer is quite large, so lazy load it in parallel with loading the data -->
3438
{#await Promise.all([loadAssetData(), import('./photo-sphere-viewer-adapter.svelte'), ...photoSphereConfigs])}
3539
<LoadingSpinner />
3640
{:then [data, module, adapter, plugins, navbar]}
37-
<svelte:component this={module.default} panorama={data} plugins={plugins ?? undefined} {navbar} {adapter} />
41+
<svelte:component
42+
this={module.default}
43+
panorama={data}
44+
plugins={plugins ?? undefined}
45+
{navbar}
46+
{adapter}
47+
{originalImageUrl}
48+
/>
3849
{:catch}
3950
{$t('errors.failed_to_load_asset')}
4051
{/await}

Diff for: web/src/lib/components/asset-viewer/photo-sphere-viewer-adapter.svelte

+16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script lang="ts">
22
import {
33
Viewer,
4+
events,
45
EquirectangularAdapter,
56
type PluginConstructor,
67
type AdapterConstructor,
@@ -9,6 +10,7 @@
910
import { onDestroy, onMount } from 'svelte';
1011
1112
export let panorama: string | { source: string };
13+
export let originalImageUrl: string | null;
1214
export let adapter: AdapterConstructor | [AdapterConstructor, unknown] = EquirectangularAdapter;
1315
export let plugins: (PluginConstructor | [PluginConstructor, unknown])[] = [];
1416
export let navbar = false;
@@ -28,6 +30,20 @@
2830
maxFov: 180,
2931
fisheye: true,
3032
});
33+
34+
if (originalImageUrl) {
35+
const zoomHandler = ({ zoomLevel }: events.ZoomUpdatedEvent) => {
36+
// zoomLevel range: [0, 100]
37+
if (Math.round(zoomLevel) >= 75) {
38+
// Replace the preview with the original
39+
viewer.setPanorama(originalImageUrl, { showLoader: false, speed: 150 }).catch(() => {
40+
viewer.setPanorama(panorama, { showLoader: false, speed: 0 }).catch(() => {});
41+
});
42+
viewer.removeEventListener(events.ZoomUpdatedEvent.type, zoomHandler);
43+
}
44+
};
45+
viewer.addEventListener(events.ZoomUpdatedEvent.type, zoomHandler);
46+
}
3147
});
3248
3349
onDestroy(() => {

0 commit comments

Comments
 (0)