mirror of
https://github.com/immich-app/immich.git
synced 2025-07-07 18:24:10 -04:00
Fix jitter
This commit is contained in:
parent
344c695b52
commit
6b0dcfffb8
@ -165,7 +165,13 @@
|
||||
const updateIsScrolling = () => (assetStore.scrolling = true);
|
||||
// note: don't throttle, debounch, or otherwise do this function async - it causes flicker
|
||||
const updateSlidingWindow = () => assetStore.updateSlidingWindow(element?.scrollTop || 0);
|
||||
const compensateScrollCallback = (delta: number) => element?.scrollBy(0, delta);
|
||||
const compensateScrollCallback = ({ delta, top }: { delta?: number; top?: number }) => {
|
||||
if (delta) {
|
||||
element?.scrollBy(0, delta);
|
||||
} else if (top) {
|
||||
element?.scrollTo({ top });
|
||||
}
|
||||
};
|
||||
const topSectionResizeObserver: OnResizeCallback = ({ height }) => (assetStore.topSectionHeight = height);
|
||||
|
||||
onMount(() => {
|
||||
|
@ -10,7 +10,7 @@ import {
|
||||
import { formatDateGroupTitle, fromLocalDateTime } from '$lib/utils/timeline-util';
|
||||
import { TUNABLES } from '$lib/utils/tunables';
|
||||
import { getAssetInfo, getTimeBucket, getTimeBuckets, TimeBucketSize, type AssetResponseDto } from '@immich/sdk';
|
||||
import { debounce, isEqual, throttle } from 'lodash-es';
|
||||
import { clamp, debounce, isEqual, throttle } from 'lodash-es';
|
||||
import { DateTime } from 'luxon';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
@ -218,6 +218,7 @@ export type ViewportXY = Viewport & {
|
||||
export class AssetBucket {
|
||||
// --- public ---
|
||||
#intersecting: boolean = $state(false);
|
||||
actuallyIntersecting: boolean = $state(false);
|
||||
isLoaded: boolean = $state(false);
|
||||
dateGroups: AssetDateGroup[] = $state([]);
|
||||
readonly store: AssetStore;
|
||||
@ -233,6 +234,7 @@ export class AssetBucket {
|
||||
#top: number = $state(0);
|
||||
#initialCount: number = 0;
|
||||
|
||||
percent: number = $state(0);
|
||||
// --- should be private, but is used by AssetStore ---
|
||||
|
||||
bucketCount: number = $derived(
|
||||
@ -423,7 +425,7 @@ export class AssetBucket {
|
||||
}
|
||||
|
||||
set bucketHeight(height: number) {
|
||||
const { store } = this;
|
||||
const { store, percent } = this;
|
||||
const index = store.buckets.indexOf(this);
|
||||
const bucketHeightDelta = height - this.#bucketHeight;
|
||||
const prevBucket = store.buckets[index - 1];
|
||||
@ -444,8 +446,14 @@ export class AssetBucket {
|
||||
// if the bucket is 'before' the last intersecting bucket in the sliding window
|
||||
// then adjust the scroll position by the delta, to compensate for the bucket
|
||||
// size adjustment
|
||||
if (currentIndex > 0 && index <= currentIndex) {
|
||||
store.compensateScrollCallback?.(bucketHeightDelta);
|
||||
if (currentIndex > 0) {
|
||||
if (index < currentIndex) {
|
||||
store.compensateScrollCallback?.({ delta: bucketHeightDelta });
|
||||
} else if (currentIndex == currentIndex) {
|
||||
this.store.updateIntersections();
|
||||
const top = this.#top + height * percent;
|
||||
store.compensateScrollCallback?.({ top });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -539,7 +547,7 @@ export class AssetStore {
|
||||
scrubberTimelineHeight: number = $state(0);
|
||||
|
||||
// -- should be private, but used by AssetBucket
|
||||
compensateScrollCallback: ((delta: number) => void) | undefined;
|
||||
compensateScrollCallback: (({ delta, top }: { delta?: number; top?: number }) => void) | undefined;
|
||||
topIntersectingBucket: AssetBucket | undefined = $state();
|
||||
|
||||
visibleWindow = $derived.by(() => ({
|
||||
@ -704,29 +712,51 @@ export class AssetStore {
|
||||
let topIntersectingBucket = undefined;
|
||||
for (const bucket of this.buckets) {
|
||||
this.#updateIntersection(bucket);
|
||||
if (!topIntersectingBucket && bucket.intersecting) {
|
||||
if (!topIntersectingBucket && bucket.actuallyIntersecting) {
|
||||
topIntersectingBucket = bucket;
|
||||
}
|
||||
}
|
||||
if (this.topIntersectingBucket !== topIntersectingBucket) {
|
||||
this.topIntersectingBucket = topIntersectingBucket;
|
||||
}
|
||||
for (const bucket of this.buckets) {
|
||||
if (bucket === this.topIntersectingBucket) {
|
||||
this.topIntersectingBucket.percent = clamp(
|
||||
(this.visibleWindow.top - this.topIntersectingBucket.top) / this.topIntersectingBucket.bucketHeight,
|
||||
0,
|
||||
1,
|
||||
);
|
||||
} else {
|
||||
bucket.percent = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#updateIntersection(bucket: AssetBucket) {
|
||||
#calculateIntersecting(bucket: AssetBucket, expandTop: number, expandBottom: number) {
|
||||
const bucketTop = bucket.top;
|
||||
const bucketBottom = bucketTop + bucket.bucketHeight;
|
||||
const topWindow = this.visibleWindow.top - INTERSECTION_EXPAND_TOP;
|
||||
const bottomWindow = this.visibleWindow.bottom + INTERSECTION_EXPAND_BOTTOM;
|
||||
const topWindow = this.visibleWindow.top - expandTop;
|
||||
const bottomWindow = this.visibleWindow.bottom + expandBottom;
|
||||
|
||||
// a bucket intersections if
|
||||
// 1) bucket's bottom is in the visible range -or-
|
||||
// 2) bucket's bottom is in the visible range -or-
|
||||
// 3) bucket's top is above visible range and bottom is below visible range
|
||||
bucket.intersecting =
|
||||
return (
|
||||
(bucketTop >= topWindow && bucketTop < bottomWindow) ||
|
||||
(bucketBottom >= topWindow && bucketBottom < bottomWindow) ||
|
||||
(bucketTop < topWindow && bucketBottom >= bottomWindow);
|
||||
(bucketTop < topWindow && bucketBottom >= bottomWindow)
|
||||
);
|
||||
}
|
||||
|
||||
#updateIntersection(bucket: AssetBucket) {
|
||||
const actuallyIntersecting = this.#calculateIntersecting(bucket, 0, 0);
|
||||
let preIntersecting = false;
|
||||
if (!actuallyIntersecting) {
|
||||
preIntersecting = this.#calculateIntersecting(bucket, INTERSECTION_EXPAND_TOP, INTERSECTION_EXPAND_BOTTOM);
|
||||
}
|
||||
bucket.intersecting = actuallyIntersecting || preIntersecting;
|
||||
bucket.actuallyIntersecting = actuallyIntersecting;
|
||||
}
|
||||
|
||||
#processPendingChanges = throttle(() => {
|
||||
@ -743,7 +773,7 @@ export class AssetStore {
|
||||
this.#pendingChanges = [];
|
||||
}, 2500);
|
||||
|
||||
setCompensateScrollCallback(compensateScrollCallback?: (delta: number) => void) {
|
||||
setCompensateScrollCallback(compensateScrollCallback?: ({ delta, top }: { delta?: number; top?: number }) => void) {
|
||||
this.compensateScrollCallback = compensateScrollCallback;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user