diff --git a/web/src/lib/components/assets/thumbnail/thumbnail.svelte b/web/src/lib/components/assets/thumbnail/thumbnail.svelte
index d3e2a1ec18..6aa72dba74 100644
--- a/web/src/lib/components/assets/thumbnail/thumbnail.svelte
+++ b/web/src/lib/components/assets/thumbnail/thumbnail.svelte
@@ -34,7 +34,7 @@
thumbnailSize?: number;
thumbnailWidth?: number;
thumbnailHeight?: number;
- actuallyIntersecting?: boolean;
+ intersecting?: boolean;
selected?: boolean;
selectionCandidate?: boolean;
disabled?: boolean;
@@ -57,7 +57,7 @@
thumbnailSize = undefined,
thumbnailWidth = undefined,
thumbnailHeight = undefined,
- actuallyIntersecting = true,
+ intersecting = true,
selected = false,
selectionCandidate = false,
disabled = false,
@@ -89,7 +89,7 @@
$effect(() => {
if (loaded && !loadedEffectRan) {
loadedEffectRan = true;
- if (!actuallyIntersecting) {
+ if (!intersecting) {
skipFade = true;
}
}
diff --git a/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte b/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte
index 713e09976f..badf6d3557 100644
--- a/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte
+++ b/web/src/lib/components/shared-components/gallery-viewer/gallery-viewer.svelte
@@ -14,7 +14,6 @@
import { assetViewingStore } from '$lib/stores/asset-viewing.store';
import { showDeleteModal } from '$lib/stores/preferences.store';
import { handlePromiseError } from '$lib/utils';
- import { TUNABLES } from '$lib/utils/tunables';
import { deleteAssets } from '$lib/utils/actions';
import {
archiveAssets,
@@ -28,6 +27,7 @@
import { getJustifiedLayoutFromAssets } from '$lib/utils/layout-utils';
import { navigate } from '$lib/utils/navigation';
import { isTimelineAsset, toTimelineAsset } from '$lib/utils/timeline-util';
+ import { TUNABLES } from '$lib/utils/tunables';
import { AssetVisibility, type AssetResponseDto } from '@immich/sdk';
import { modalManager } from '@immich/ui';
import { debounce } from 'lodash-es';
@@ -82,14 +82,14 @@
return `top: ${geo.getTop(i)}px; left: ${geo.getLeft(i)}px; width: ${geo.getWidth(i)}px; height: ${geo.getHeight(i)}px;`;
};
- const isIntersecting = (i: number) => {
+ const isRenderable = (i: number) => {
const geo = geometry;
const window = slidingWindow;
const top = geo.getTop(i);
return top + pageHeaderOffset < window.bottom && top + geo.getHeight(i) > window.top;
};
- const isActuallyIntersecting = (i: number) => {
+ const isIntersecting = (i: number) => {
const geo = geometry;
const top = geo.getTop(i) + pageHeaderOffset;
const bottom = top + geo.getHeight(i);
@@ -387,7 +387,7 @@
style:width={geometry.containerWidth + 'px'}
>
{#each assets as asset, i (asset.id + '-' + i)}
- {#if isIntersecting(i)}
+ {#if isRenderable(i)}
{@const currentAsset = toTimelineAsset(asset)}
diff --git a/web/src/lib/components/timeline/AssetLayout.svelte b/web/src/lib/components/timeline/AssetLayout.svelte
index cf4090bc1f..c80ac01760 100644
--- a/web/src/lib/components/timeline/AssetLayout.svelte
+++ b/web/src/lib/components/timeline/AssetLayout.svelte
@@ -1,5 +1,6 @@
- {#each filterIntersecting(viewerAssets) as viewerAsset (viewerAsset.id)}
+ {#each filterRenderable(viewerAssets) as viewerAsset (viewerAsset.id)}
{@const position = viewerAsset.position!}
{@const asset = viewerAsset.asset!}
- {@const actuallyIntersecting = viewerAsset.actuallyIntersecting!}
+ {@const intersecting = viewerAsset.intersecting!}
- {@render thumbnail({ asset, position, actuallyIntersecting })}
+ {@render thumbnail({ asset, position, intersecting })}
{@render customThumbnailLayout?.(asset)}
{/each}
diff --git a/web/src/lib/components/timeline/Month.svelte b/web/src/lib/components/timeline/Month.svelte
index b6c4e50a1e..013d620df1 100644
--- a/web/src/lib/components/timeline/Month.svelte
+++ b/web/src/lib/components/timeline/Month.svelte
@@ -3,7 +3,7 @@
import { DayGroup } from '$lib/managers/timeline-manager/day-group.svelte';
import type { MonthGroup } from '$lib/managers/timeline-manager/month-group.svelte';
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
- import { assetsSnapshot } from '$lib/managers/timeline-manager/utils.svelte';
+ import { assetsSnapshot, filterRenderable } from '$lib/managers/timeline-manager/utils.svelte';
import type { VirtualScrollManager } from '$lib/managers/VirtualScrollManager/VirtualScrollManager.svelte';
import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
import { uploadAssetsStore } from '$lib/stores/upload';
@@ -21,7 +21,7 @@
position: CommonPosition;
dayGroup: DayGroup;
groupIndex: number;
- actuallyIntersecting: boolean;
+ intersecting: boolean;
},
]
>;
@@ -47,10 +47,6 @@
const transitionDuration = $derived(monthGroup.timelineManager.suspendTransitions && !$isUploading ? 0 : 150);
- const filterIntersecting =
(intersectables: T[]) => {
- return intersectables.filter(({ intersecting }) => intersecting);
- };
-
const getDayGroupFullDate = (dayGroup: DayGroup): string => {
const { month, year } = dayGroup.monthGroup.yearMonth;
const date = fromTimelinePlainDate({
@@ -62,7 +58,7 @@
};
-{#each filterIntersecting(monthGroup.dayGroups) as dayGroup, groupIndex (dayGroup.day)}
+{#each filterRenderable(monthGroup.dayGroups) as dayGroup, groupIndex (dayGroup.day)}
{@const isDayGroupSelected = assetInteraction.selectedGroup.has(dayGroup.groupTitle)}
- {#snippet thumbnail({ asset, position, actuallyIntersecting })}
- {@render thumbnailWithGroup({ asset, position, dayGroup, groupIndex, actuallyIntersecting })}
+ {#snippet thumbnail({ asset, position, intersecting })}
+ {@render thumbnailWithGroup({ asset, position, dayGroup, groupIndex, intersecting })}
{/snippet}
diff --git a/web/src/lib/components/timeline/Timeline.svelte b/web/src/lib/components/timeline/Timeline.svelte
index cafd867295..431034492f 100644
--- a/web/src/lib/components/timeline/Timeline.svelte
+++ b/web/src/lib/components/timeline/Timeline.svelte
@@ -645,7 +645,7 @@
{#each timelineManager.months as monthGroup (monthGroup.viewId)}
- {@const display = monthGroup.intersecting}
+ {@const renderable = monthGroup.renderable}
{@const absoluteHeight = monthGroup.top}
{#if !monthGroup.isLoaded}
@@ -657,7 +657,7 @@
>
- {:else if display}
+ {:else if renderable}
- {#snippet thumbnail({ asset, position, dayGroup, groupIndex, actuallyIntersecting })}
+ {#snippet thumbnail({ asset, position, dayGroup, groupIndex, intersecting })}
{@const isAssetSelectionCandidate = assetInteraction.hasSelectionCandidate(asset.id)}
{@const isAssetSelected =
assetInteraction.hasSelectedAsset(asset.id) || timelineManager.albumAssets.has(asset.id)}
@@ -684,7 +684,7 @@
{asset}
{albumUsers}
{groupIndex}
- {actuallyIntersecting}
+ {intersecting}
onClick={(asset) => {
if (typeof onThumbnailClick === 'function') {
onThumbnailClick(asset, timelineManager, dayGroup, _onClick);
diff --git a/web/src/lib/managers/timeline-manager/day-group.svelte.ts b/web/src/lib/managers/timeline-manager/day-group.svelte.ts
index 75793f598e..f331613e68 100644
--- a/web/src/lib/managers/timeline-manager/day-group.svelte.ts
+++ b/web/src/lib/managers/timeline-manager/day-group.svelte.ts
@@ -18,7 +18,7 @@ export class DayGroup {
height = $state(0);
width = $state(0);
- intersecting = $derived.by(() => this.viewerAssets.some((viewAsset) => viewAsset.intersecting));
+ renderable = $derived.by(() => this.viewerAssets.some((viewAsset) => viewAsset.renderable));
#top: number = $state(0);
#start: number = $state(0);
@@ -137,7 +137,7 @@ export class DayGroup {
}
layout(options: CommonLayoutOptions, noDefer: boolean) {
- if (!noDefer && !this.monthGroup.intersecting && !this.monthGroup.timelineManager.isScrollingOnLoad) {
+ if (!noDefer && !this.monthGroup.renderable && !this.monthGroup.timelineManager.isScrollingOnLoad) {
this.#deferredLayout = true;
return;
}
diff --git a/web/src/lib/managers/timeline-manager/internal/intersection-support.svelte.spec.ts b/web/src/lib/managers/timeline-manager/internal/intersection-support.svelte.spec.ts
index 4b2a7aa460..dd7699cfe1 100644
--- a/web/src/lib/managers/timeline-manager/internal/intersection-support.svelte.spec.ts
+++ b/web/src/lib/managers/timeline-manager/internal/intersection-support.svelte.spec.ts
@@ -1,6 +1,12 @@
import { describe, expect, it } from 'vitest';
import type { TimelineManager } from '../timeline-manager.svelte';
-import { Intersection, calculateViewerAssetIntersecting, isIntersecting } from './intersection-support.svelte';
+import {
+ IntersectionFlags,
+ calculateViewerAssetIntersecting,
+ isIntersecting,
+ isRenderable,
+ isVisible,
+} from './intersection-support.svelte';
function createMockTimelineManager(windowTop: number, windowBottom: number, headerHeight: number = 0): TimelineManager {
return {
@@ -51,45 +57,87 @@ describe('calculateViewerAssetIntersecting', () => {
// viewport 0-1000, no header, default expand margins 500/500
const manager = createMockTimelineManager(0, 1000);
- it('should return ACTUAL when asset is within viewport', () => {
- expect(calculateViewerAssetIntersecting(manager, 100, 50)).toBe(Intersection.ACTUAL);
+ it('should return VISIBLE when asset is within viewport', () => {
+ expect(calculateViewerAssetIntersecting(manager, 100, 50)).toBe(IntersectionFlags.VISIBLE);
});
- it('should return ACTUAL when asset is at viewport top edge', () => {
- expect(calculateViewerAssetIntersecting(manager, 0, 50)).toBe(Intersection.ACTUAL);
+ it('should return VISIBLE when asset is at viewport top edge', () => {
+ expect(calculateViewerAssetIntersecting(manager, 0, 50)).toBe(IntersectionFlags.VISIBLE);
});
- it('should return ACTUAL when asset partially overlaps viewport bottom', () => {
- expect(calculateViewerAssetIntersecting(manager, 980, 50)).toBe(Intersection.ACTUAL);
+ it('should return VISIBLE when asset partially overlaps viewport bottom', () => {
+ expect(calculateViewerAssetIntersecting(manager, 980, 50)).toBe(IntersectionFlags.VISIBLE);
});
- it('should return PRE when asset is just above viewport within expand margin', () => {
- expect(calculateViewerAssetIntersecting(manager, -200, 50)).toBe(Intersection.PRE);
+ it('should return NEARBY when asset is just above viewport within expand margin', () => {
+ expect(calculateViewerAssetIntersecting(manager, -200, 50)).toBe(IntersectionFlags.NEARBY);
});
- it('should return PRE when asset is just below viewport within expand margin', () => {
- expect(calculateViewerAssetIntersecting(manager, 1200, 50)).toBe(Intersection.PRE);
+ it('should return NEARBY when asset is just below viewport within expand margin', () => {
+ expect(calculateViewerAssetIntersecting(manager, 1200, 50)).toBe(IntersectionFlags.NEARBY);
});
it('should return NONE when asset is far above viewport', () => {
- expect(calculateViewerAssetIntersecting(manager, -1000, 50)).toBe(Intersection.NONE);
+ expect(calculateViewerAssetIntersecting(manager, -1000, 50)).toBe(IntersectionFlags.NONE);
});
it('should return NONE when asset is far below viewport', () => {
- expect(calculateViewerAssetIntersecting(manager, 2000, 50)).toBe(Intersection.NONE);
+ expect(calculateViewerAssetIntersecting(manager, 2000, 50)).toBe(IntersectionFlags.NONE);
});
it('should account for header height in viewport bounds', () => {
const managerWithHeader = createMockTimelineManager(100, 500, 50);
// viewport effectively becomes (100-50)=50 to (500+50)=550
// asset at 40-90 overlaps the effective viewport
- expect(calculateViewerAssetIntersecting(managerWithHeader, 40, 50)).toBe(Intersection.ACTUAL);
+ expect(calculateViewerAssetIntersecting(managerWithHeader, 40, 50)).toBe(IntersectionFlags.VISIBLE);
});
- it('should return PRE not ACTUAL for asset outside viewport but within header-adjusted expand', () => {
+ it('should return NEARBY not VISIBLE for asset outside viewport but within header-adjusted expand', () => {
const managerWithHeader = createMockTimelineManager(100, 500, 50);
// effective viewport: 50-550, expand: 500 each way -> -450 to 1050
// asset at -400 to -350 is outside viewport but within expand
- expect(calculateViewerAssetIntersecting(managerWithHeader, -400, 50)).toBe(Intersection.PRE);
+ expect(calculateViewerAssetIntersecting(managerWithHeader, -400, 50)).toBe(IntersectionFlags.NEARBY);
+ });
+});
+
+describe('Intersection flags', () => {
+ it('RENDERABLE should be NEARBY | VISIBLE', () => {
+ expect(IntersectionFlags.RENDERABLE).toBe(IntersectionFlags.NEARBY | IntersectionFlags.VISIBLE);
+ });
+});
+
+describe('isVisible', () => {
+ it('should return true for VISIBLE', () => {
+ expect(isVisible(IntersectionFlags.VISIBLE)).toBe(true);
+ });
+
+ it('should return true for RENDERABLE', () => {
+ expect(isVisible(IntersectionFlags.RENDERABLE)).toBe(true);
+ });
+
+ it('should return false for NEARBY', () => {
+ expect(isVisible(IntersectionFlags.NEARBY)).toBe(false);
+ });
+
+ it('should return false for NONE', () => {
+ expect(isVisible(IntersectionFlags.NONE)).toBe(false);
+ });
+});
+
+describe('isRenderable', () => {
+ it('should return true for VISIBLE', () => {
+ expect(isRenderable(IntersectionFlags.VISIBLE)).toBe(true);
+ });
+
+ it('should return true for NEARBY', () => {
+ expect(isRenderable(IntersectionFlags.NEARBY)).toBe(true);
+ });
+
+ it('should return true for RENDERABLE', () => {
+ expect(isRenderable(IntersectionFlags.RENDERABLE)).toBe(true);
+ });
+
+ it('should return false for NONE', () => {
+ expect(isRenderable(IntersectionFlags.NONE)).toBe(false);
});
});
diff --git a/web/src/lib/managers/timeline-manager/internal/intersection-support.svelte.ts b/web/src/lib/managers/timeline-manager/internal/intersection-support.svelte.ts
index 3810942d81..7fa629bb5f 100644
--- a/web/src/lib/managers/timeline-manager/internal/intersection-support.svelte.ts
+++ b/web/src/lib/managers/timeline-manager/internal/intersection-support.svelte.ts
@@ -1,3 +1,4 @@
+/* eslint-disable unicorn/prefer-math-trunc */
import { TUNABLES } from '$lib/utils/tunables';
import type { MonthGroup } from '../month-group.svelte';
import { TimelineManager } from '../timeline-manager.svelte';
@@ -7,75 +8,72 @@ const {
} = TUNABLES;
/**
- * General function to check if a rectangular region intersects with a window.
+ * General function to check if a rectangular region intersects with another regtangular region.
*/
-export function isIntersecting(regionTop: number, regionBottom: number, windowTop: number, windowBottom: number) {
+export function isIntersecting(regionTop: number, regionBottom: number, otherTop: number, otherBottom: number) {
return (
- (regionTop >= windowTop && regionTop < windowBottom) ||
- (regionBottom >= windowTop && regionBottom < windowBottom) ||
- (regionTop < windowTop && regionBottom >= windowBottom)
+ (regionTop >= otherTop && regionTop < otherBottom) ||
+ (regionBottom >= otherTop && regionBottom < otherBottom) ||
+ (regionTop < otherTop && regionBottom >= otherBottom)
);
}
-export function updateIntersectionMonthGroup(timelineManager: TimelineManager, month: MonthGroup) {
- const monthGroupTop = month.top;
- const monthGroupBottom = monthGroupTop + month.height;
- const windowTop = timelineManager.visibleWindow.top;
- const windowBottom = timelineManager.visibleWindow.bottom;
+const NEARBY = 1 << 0;
+const VISIBLE = 1 << 1;
- const actuallyIntersecting = isIntersecting(monthGroupTop, monthGroupBottom, windowTop, windowBottom);
+export const IntersectionFlags = {
+ NONE: 0,
+ NEARBY,
+ VISIBLE,
+ RENDERABLE: NEARBY | VISIBLE,
+} as const;
- let intersecting = actuallyIntersecting;
- if (!actuallyIntersecting) {
- intersecting = isIntersecting(
- monthGroupTop,
- monthGroupBottom,
- windowTop - INTERSECTION_EXPAND_TOP,
- windowBottom + INTERSECTION_EXPAND_BOTTOM,
- );
+export type IntersectionFlag = (typeof IntersectionFlags)[keyof typeof IntersectionFlags];
+
+export function isVisible(flag: number): boolean {
+ return (flag & IntersectionFlags.VISIBLE) !== 0;
+}
+
+export function isRenderable(flag: number): boolean {
+ return (flag & IntersectionFlags.RENDERABLE) !== 0;
+}
+
+function calculateIntersection(regionTop: number, regionBottom: number, windowTop: number, windowBottom: number) {
+ if (regionBottom < windowTop - INTERSECTION_EXPAND_TOP || regionTop >= windowBottom + INTERSECTION_EXPAND_BOTTOM) {
+ return IntersectionFlags.NONE;
}
- month.intersecting = intersecting;
- month.actuallyIntersecting = actuallyIntersecting;
- if (intersecting) {
+ if (regionBottom < windowTop || regionTop >= windowBottom) {
+ return IntersectionFlags.NEARBY;
+ }
+
+ return IntersectionFlags.VISIBLE;
+}
+
+export function updateIntersectionMonthGroup(timelineManager: TimelineManager, month: MonthGroup) {
+ const intersection = calculateIntersection(
+ month.top,
+ month.top + month.height,
+ timelineManager.visibleWindow.top,
+ timelineManager.visibleWindow.bottom,
+ );
+
+ month.intersection = intersection;
+ if (isRenderable(intersection)) {
timelineManager.clearDeferredLayout(month);
}
}
-// Bit flags for intersection state
-export const Intersection = {
- NONE: 0,
- PRE: 1,
- ACTUAL: 3, // includes PRE (both bits set)
-} as const;
-
-/**
- * Returns a numeric flag: NONE (0), PRE (1, within expanded margin only), or ACTUAL (3, truly visible).
- */
export function calculateViewerAssetIntersecting(
timelineManager: TimelineManager,
positionTop: number,
positionHeight: number,
) {
- const positionBottom = positionTop + positionHeight;
const headerHeight = timelineManager.headerHeight;
- const windowTop = timelineManager.visibleWindow.top - headerHeight;
- const windowBottom = timelineManager.visibleWindow.bottom + headerHeight;
-
- if (isIntersecting(positionTop, positionBottom, windowTop, windowBottom)) {
- return Intersection.ACTUAL;
- }
-
- if (
- isIntersecting(
- positionTop,
- positionBottom,
- windowTop - INTERSECTION_EXPAND_TOP,
- windowBottom + INTERSECTION_EXPAND_BOTTOM,
- )
- ) {
- return Intersection.PRE;
- }
-
- return Intersection.NONE;
+ return calculateIntersection(
+ positionTop,
+ positionTop + positionHeight,
+ timelineManager.visibleWindow.top - headerHeight,
+ timelineManager.visibleWindow.bottom + headerHeight,
+ );
}
diff --git a/web/src/lib/managers/timeline-manager/month-group.svelte.ts b/web/src/lib/managers/timeline-manager/month-group.svelte.ts
index b41deb5785..e9391dd5e4 100644
--- a/web/src/lib/managers/timeline-manager/month-group.svelte.ts
+++ b/web/src/lib/managers/timeline-manager/month-group.svelte.ts
@@ -17,6 +17,12 @@ import {
import { t } from 'svelte-i18n';
import { get } from 'svelte/store';
+import {
+ IntersectionFlags,
+ isRenderable,
+ isVisible,
+ type IntersectionFlag,
+} from '$lib/managers/timeline-manager/internal/intersection-support.svelte';
import { SvelteSet } from 'svelte/reactivity';
import { DayGroup } from './day-group.svelte';
import { GroupInsertionCache } from './group-insertion-cache.svelte';
@@ -25,8 +31,7 @@ import type { AssetDescriptor, Direction, MoveAsset, TimelineAsset } from './typ
import { ViewerAsset } from './viewer-asset.svelte';
export class MonthGroup {
- #intersecting: boolean = $state(false);
- actuallyIntersecting: boolean = $state(false);
+ #intersection: IntersectionFlag = $state(IntersectionFlags.NONE);
isLoaded: boolean = $state(false);
dayGroups: DayGroup[] = $state([]);
readonly timelineManager: TimelineManager;
@@ -78,21 +83,25 @@ export class MonthGroup {
}
}
- set intersecting(newValue: boolean) {
- const old = this.#intersecting;
+ set intersection(newValue: IntersectionFlag) {
+ const old = this.#intersection;
if (old === newValue) {
return;
}
- this.#intersecting = newValue;
- if (newValue) {
+ this.#intersection = newValue;
+ if (isRenderable(newValue)) {
void this.timelineManager.loadMonthGroup(this.yearMonth);
} else {
this.cancel();
}
}
+ get renderable() {
+ return isRenderable(this.#intersection);
+ }
+
get intersecting() {
- return this.#intersecting;
+ return isVisible(this.#intersection);
}
get lastDayGroup() {
diff --git a/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts b/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts
index 38c593bd00..52217d4225 100644
--- a/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts
+++ b/web/src/lib/managers/timeline-manager/timeline-manager.svelte.ts
@@ -208,7 +208,7 @@ export class TimelineManager extends VirtualScrollManager {
updateIntersectionMonthGroup(this, month);
}
- const month = this.months.find((month) => month.actuallyIntersecting);
+ const month = this.months.find((month) => month.intersecting);
const viewportTopRatioInMonth = this.#calculateVewportTopRatioInMonth(month);
const monthBottomViewportRatio = this.#calculateMonthBottomViewportRatio(month);
diff --git a/web/src/lib/managers/timeline-manager/utils.svelte.ts b/web/src/lib/managers/timeline-manager/utils.svelte.ts
index 2aba6470ee..4cd9476162 100644
--- a/web/src/lib/managers/timeline-manager/utils.svelte.ts
+++ b/web/src/lib/managers/timeline-manager/utils.svelte.ts
@@ -2,3 +2,7 @@ import type { TimelineAsset } from './types';
export const assetSnapshot = (asset: TimelineAsset): TimelineAsset => $state.snapshot(asset);
export const assetsSnapshot = (assets: TimelineAsset[]) => assets.map((asset) => $state.snapshot(asset));
+
+export function filterRenderable(items: T[]) {
+ return items.filter(({ renderable }) => renderable);
+}
diff --git a/web/src/lib/managers/timeline-manager/viewer-asset.svelte.ts b/web/src/lib/managers/timeline-manager/viewer-asset.svelte.ts
index 10299c83eb..f0096f4d98 100644
--- a/web/src/lib/managers/timeline-manager/viewer-asset.svelte.ts
+++ b/web/src/lib/managers/timeline-manager/viewer-asset.svelte.ts
@@ -1,7 +1,12 @@
import type { CommonPosition } from '$lib/utils/layout-utils';
import type { DayGroup } from './day-group.svelte';
-import { Intersection, calculateViewerAssetIntersecting } from './internal/intersection-support.svelte';
+import {
+ IntersectionFlags,
+ calculateViewerAssetIntersecting,
+ isRenderable,
+ isVisible,
+} from './internal/intersection-support.svelte';
import type { TimelineAsset } from './types';
export class ViewerAsset {
@@ -9,7 +14,7 @@ export class ViewerAsset {
#intersection = $derived.by(() => {
if (!this.position) {
- return Intersection.NONE;
+ return IntersectionFlags.NONE;
}
const store = this.#group.monthGroup.timelineManager;
@@ -18,12 +23,12 @@ export class ViewerAsset {
return calculateViewerAssetIntersecting(store, positionTop, this.position.height);
});
- get intersecting() {
- return this.#intersection !== Intersection.NONE;
+ get renderable() {
+ return isRenderable(this.#intersection);
}
- get actuallyIntersecting() {
- return this.#intersection === Intersection.ACTUAL;
+ get intersecting() {
+ return isVisible(this.#intersection);
}
position: CommonPosition | undefined = $state.raw();