@cratis/components 4.26.3 → 4.26.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/compat-manifest.json +11 -11
- package/dist/esm/PivotViewer/components/pivot/sprites.js +1 -1
- package/dist/esm/PivotViewer/components/pivot/syncScrollSprites.d.ts +2 -2
- package/dist/esm/PivotViewer/components/pivot/syncScrollSprites.d.ts.map +1 -1
- package/dist/esm/PivotViewer/components/pivot/syncScrollSprites.js +1 -1
- package/dist/esm/PivotViewer/components/pivot/syncScrollSprites.js.map +1 -1
- package/dist/esm/PivotViewer/components/pivot/usePivotScrollSync.d.ts.map +1 -1
- package/dist/esm/PivotViewer/components/pivot/usePivotScrollSync.js +8 -2
- package/dist/esm/PivotViewer/components/pivot/usePivotScrollSync.js.map +1 -1
- package/dist/esm/PivotViewer/components/pivot/usePivotSpriteSync.d.ts.map +1 -1
- package/dist/esm/PivotViewer/components/pivot/usePivotSpriteSync.js +49 -28
- package/dist/esm/PivotViewer/components/pivot/usePivotSpriteSync.js.map +1 -1
- package/dist/esm/PivotViewer/components/pivot/visibility.d.ts +11 -1
- package/dist/esm/PivotViewer/components/pivot/visibility.d.ts.map +1 -1
- package/dist/esm/PivotViewer/components/pivot/visibility.js +44 -6
- package/dist/esm/PivotViewer/components/pivot/visibility.js.map +1 -1
- package/package.json +1 -1
package/compat-manifest.json
CHANGED
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
{
|
|
69
69
|
"name": "@cratis/components",
|
|
70
70
|
"role": "core",
|
|
71
|
-
"version": "4.26.
|
|
71
|
+
"version": "4.26.4",
|
|
72
72
|
"releaseMajorRange": ">=4 <5",
|
|
73
73
|
"independentRelease": false,
|
|
74
74
|
"private": false,
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
{
|
|
93
93
|
"name": "@cratis/eslint-plugin-components",
|
|
94
94
|
"role": "eslint",
|
|
95
|
-
"version": "4.26.
|
|
95
|
+
"version": "4.26.4",
|
|
96
96
|
"releaseMajorRange": ">=4 <5",
|
|
97
97
|
"independentRelease": false,
|
|
98
98
|
"private": false,
|
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
{
|
|
106
106
|
"name": "@cratis/components.migrator",
|
|
107
107
|
"role": "migrator",
|
|
108
|
-
"version": "4.26.
|
|
108
|
+
"version": "4.26.4",
|
|
109
109
|
"releaseMajorRange": ">=4 <5",
|
|
110
110
|
"independentRelease": false,
|
|
111
111
|
"private": false,
|
|
@@ -116,13 +116,13 @@
|
|
|
116
116
|
{
|
|
117
117
|
"name": "@cratis/components.conformance",
|
|
118
118
|
"role": "conformance",
|
|
119
|
-
"version": "4.26.
|
|
119
|
+
"version": "4.26.4",
|
|
120
120
|
"releaseMajorRange": ">=4 <5",
|
|
121
121
|
"independentRelease": false,
|
|
122
122
|
"private": false,
|
|
123
123
|
"packageAccess": "public",
|
|
124
124
|
"peerDependencies": {
|
|
125
|
-
"@cratis/components": "4.26.
|
|
125
|
+
"@cratis/components": "4.26.4",
|
|
126
126
|
"react": "^19.0.0",
|
|
127
127
|
"react-dom": "^19.0.0"
|
|
128
128
|
},
|
|
@@ -132,13 +132,13 @@
|
|
|
132
132
|
{
|
|
133
133
|
"name": "@cratis/components.mui",
|
|
134
134
|
"role": "renderer-adapter",
|
|
135
|
-
"version": "4.26.
|
|
135
|
+
"version": "4.26.4",
|
|
136
136
|
"releaseMajorRange": ">=4 <5",
|
|
137
137
|
"independentRelease": false,
|
|
138
138
|
"private": false,
|
|
139
139
|
"packageAccess": "public",
|
|
140
140
|
"peerDependencies": {
|
|
141
|
-
"@cratis/components": "4.26.
|
|
141
|
+
"@cratis/components": "4.26.4",
|
|
142
142
|
"@emotion/react": ">=11.5 <12",
|
|
143
143
|
"@emotion/styled": ">=11.11 <12",
|
|
144
144
|
"@mui/material": ">=9 <10",
|
|
@@ -188,13 +188,13 @@
|
|
|
188
188
|
{
|
|
189
189
|
"name": "@cratis/components.primereact",
|
|
190
190
|
"role": "renderer-adapter",
|
|
191
|
-
"version": "4.26.
|
|
191
|
+
"version": "4.26.4",
|
|
192
192
|
"releaseMajorRange": ">=4 <5",
|
|
193
193
|
"independentRelease": false,
|
|
194
194
|
"private": false,
|
|
195
195
|
"packageAccess": "public",
|
|
196
196
|
"peerDependencies": {
|
|
197
|
-
"@cratis/components": "4.26.
|
|
197
|
+
"@cratis/components": "4.26.4",
|
|
198
198
|
"@primereact/core": ">=11 <12",
|
|
199
199
|
"@primereact/ui": ">=11 <12",
|
|
200
200
|
"@primeuix/themes": ">=3 <4",
|
|
@@ -256,13 +256,13 @@
|
|
|
256
256
|
{
|
|
257
257
|
"name": "@cratis/components.primereact10",
|
|
258
258
|
"role": "renderer-adapter",
|
|
259
|
-
"version": "4.26.
|
|
259
|
+
"version": "4.26.4",
|
|
260
260
|
"releaseMajorRange": ">=4 <5",
|
|
261
261
|
"independentRelease": false,
|
|
262
262
|
"private": false,
|
|
263
263
|
"packageAccess": "public",
|
|
264
264
|
"peerDependencies": {
|
|
265
|
-
"@cratis/components": "4.26.
|
|
265
|
+
"@cratis/components": "4.26.4",
|
|
266
266
|
"primereact": ">=10.9.9 <11",
|
|
267
267
|
"react": "^19.0.0",
|
|
268
268
|
"react-dom": "^19.0.0"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as PIXI from 'pixi.js';
|
|
2
|
-
import { CARD_RADIUS,
|
|
2
|
+
import { CARD_RADIUS, CARD_PADDING, CARD_GAP } from './constants.js';
|
|
3
3
|
import { ellipsizeLine, ellipsizeBlock } from './ellipsize.js';
|
|
4
4
|
|
|
5
5
|
const VALUES_INSET = 65;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { LayoutResult } from '../../engine/types.js';
|
|
2
|
-
import { type SyncParams } from './visibility.js';
|
|
2
|
+
import { type SyncParams, type SyncResult } from './visibility.js';
|
|
3
3
|
/** Keep the scroll path's transition layout in sync with the normal render path. */
|
|
4
|
-
export declare function syncScrollSprites<TItem>(params: Omit<SyncParams<TItem>, 'prevLayout'>, previousLayout: LayoutResult | null):
|
|
4
|
+
export declare function syncScrollSprites<TItem>(params: Omit<SyncParams<TItem>, 'prevLayout'>, previousLayout: LayoutResult | null): SyncResult;
|
|
5
5
|
//# sourceMappingURL=syncScrollSprites.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"syncScrollSprites.d.ts","sourceRoot":"","sources":["../../../../../PivotViewer/components/pivot/syncScrollSprites.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAoB,CAAC;AACvD,OAAO,EAAyB,KAAK,UAAU,EAAE,MAAM,iBAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"syncScrollSprites.d.ts","sourceRoot":"","sources":["../../../../../PivotViewer/components/pivot/syncScrollSprites.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAoB,CAAC;AACvD,OAAO,EAAyB,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAc,CAAC;AAEvF,oFAAoF;AACpF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC,EAAE,cAAc,EAAE,YAAY,GAAG,IAAI,GAAG,UAAU,CAEvI"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { syncSpritesToViewport } from './visibility.js';
|
|
2
2
|
|
|
3
3
|
function syncScrollSprites(params, previousLayout) {
|
|
4
|
-
syncSpritesToViewport({ ...params, prevLayout: previousLayout });
|
|
4
|
+
return syncSpritesToViewport({ ...params, prevLayout: previousLayout });
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
export { syncScrollSprites };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"syncScrollSprites.js","sources":["../../../../../PivotViewer/components/pivot/syncScrollSprites.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport type { LayoutResult } from '../../engine/types';\nimport { syncSpritesToViewport, type SyncParams } from './visibility';\n\n/** Keep the scroll path's transition layout in sync with the normal render path. */\nexport function syncScrollSprites<TItem>(params: Omit<SyncParams<TItem>, 'prevLayout'>, previousLayout: LayoutResult | null) {\n syncSpritesToViewport({ ...params, prevLayout: previousLayout });\n}\n"],"names":[],"mappings":";;AAOM,SAAU,iBAAiB,CAAQ,MAA6C,EAAE,cAAmC,EAAA;IACvH,qBAAqB,CAAC,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"syncScrollSprites.js","sources":["../../../../../PivotViewer/components/pivot/syncScrollSprites.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport type { LayoutResult } from '../../engine/types';\nimport { syncSpritesToViewport, type SyncParams, type SyncResult } from './visibility';\n\n/** Keep the scroll path's transition layout in sync with the normal render path. */\nexport function syncScrollSprites<TItem>(params: Omit<SyncParams<TItem>, 'prevLayout'>, previousLayout: LayoutResult | null): SyncResult {\n return syncSpritesToViewport({ ...params, prevLayout: previousLayout });\n}\n"],"names":[],"mappings":";;AAOM,SAAU,iBAAiB,CAAQ,MAA6C,EAAE,cAAmC,EAAA;IACvH,OAAO,qBAAqB,CAAC,EAAE,GAAG,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC;AAC3E;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePivotScrollSync.d.ts","sourceRoot":"","sources":["../../../../../PivotViewer/components/pivot/usePivotScrollSync.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAsB,CAAC;AAE/D;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAAI,KAAK,SAAS,MAAM,+EAOpD,kBAAkB,CAAC,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"usePivotScrollSync.d.ts","sourceRoot":"","sources":["../../../../../PivotViewer/components/pivot/usePivotScrollSync.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAsB,CAAC;AAE/D;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAAI,KAAK,SAAS,MAAM,+EAOpD,kBAAkB,CAAC,KAAK,CAAC,SA6K3B,CAAC"}
|
|
@@ -17,10 +17,11 @@ const usePivotScrollSync = ({ props, stage, transition, cardColorsRef, onCardCli
|
|
|
17
17
|
const container = parentContainerRef.current;
|
|
18
18
|
const app = appRef.current;
|
|
19
19
|
const pendingRef = { scheduled: false };
|
|
20
|
+
let frameHandle = 0;
|
|
20
21
|
const processScroll = () => {
|
|
21
22
|
pendingRef.scheduled = false;
|
|
22
23
|
try {
|
|
23
|
-
syncScrollSprites({
|
|
24
|
+
const { pending } = syncScrollSprites({
|
|
24
25
|
root: rootRef.current,
|
|
25
26
|
groupsContainer: groupsContainerRef.current,
|
|
26
27
|
container: parentContainerRef.current,
|
|
@@ -47,6 +48,10 @@ const usePivotScrollSync = ({ props, stage, transition, cardColorsRef, onCardCli
|
|
|
47
48
|
prevScrollLeftRef.current = container.scrollLeft || 0;
|
|
48
49
|
needsRenderRef.current = true;
|
|
49
50
|
app.renderer?.render(app.stage);
|
|
51
|
+
if (pending) {
|
|
52
|
+
pendingRef.scheduled = true;
|
|
53
|
+
frameHandle = requestAnimationFrame(processScroll);
|
|
54
|
+
}
|
|
50
55
|
}
|
|
51
56
|
catch (e) {
|
|
52
57
|
console.error('[PivotCanvas] processScroll error', e);
|
|
@@ -55,12 +60,13 @@ const usePivotScrollSync = ({ props, stage, transition, cardColorsRef, onCardCli
|
|
|
55
60
|
const onScroll = () => {
|
|
56
61
|
if (!pendingRef.scheduled) {
|
|
57
62
|
pendingRef.scheduled = true;
|
|
58
|
-
requestAnimationFrame(processScroll);
|
|
63
|
+
frameHandle = requestAnimationFrame(processScroll);
|
|
59
64
|
}
|
|
60
65
|
};
|
|
61
66
|
container.addEventListener('scroll', onScroll, { passive: true });
|
|
62
67
|
return () => {
|
|
63
68
|
container.removeEventListener('scroll', onScroll);
|
|
69
|
+
cancelAnimationFrame(frameHandle);
|
|
64
70
|
};
|
|
65
71
|
}, [
|
|
66
72
|
pixiReady,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePivotScrollSync.js","sources":["../../../../../PivotViewer/components/pivot/usePivotScrollSync.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { useEffect } from 'react';\nimport { asReactMouseEvent } from './asReactMouseEvent';\nimport type { CardSprite } from './constants';\nimport {\n createCardSprite as createCardSpriteExternal,\n updateCardContent as updateCardContentExternal,\n} from './sprites';\nimport { syncScrollSprites } from './syncScrollSprites';\nimport type { PivotRenderContext } from './PivotRenderContext';\n\n/**\n * Syncs the card sprites once per animation frame while the viewport scrolls, natively or\n * programmatically.\n * @param context The props, stage, transition state and colors.\n */\nexport const usePivotScrollSync = <TItem extends object>({\n props,\n stage,\n transition,\n cardColorsRef,\n onCardClickRef,\n onPanStartRef,\n}: PivotRenderContext<TItem>) => {\n const {\n items,\n layout,\n grouping,\n visibleIds,\n cardWidth,\n cardHeight,\n zoomLevel,\n panX,\n panY,\n viewportWidth,\n viewportHeight,\n selectedId,\n viewMode,\n cardRenderer,\n resolveId,\n onPanStart,\n onCardClick,\n containerRef: parentContainerRef,\n } = props;\n const { rootRef, groupsContainerRef, spritesRef, appRef, needsRenderRef, pixiReady } =\n stage;\n const {\n isViewTransitionRef,\n transitionLayoutRef,\n transitionSeenIdsRef,\n prevScrollTopRef,\n prevScrollLeftRef,\n } = transition;\n\n // Listen to native scroll events on the parent container so we update the\n // Pixi world immediately when the user scrolls (native scrollbar or\n // programmatic). This ensures `syncSpritesToViewport` runs on scroll and\n // creates/destroys sprites as the viewport moves.\n useEffect(() => {\n if (\n !pixiReady ||\n !parentContainerRef ||\n !parentContainerRef.current ||\n !appRef.current ||\n !rootRef.current\n )\n return;\n\n const container = parentContainerRef.current;\n const app = appRef.current;\n\n // rAF-batched scroll handling: process scroll once per animation frame to avoid heavy synchronous work inside\n // the scroll event which causes jank and de-synchronisation between the\n // compositor and Pixi render updates.\n const pendingRef = { scheduled: false } as { scheduled: boolean };\n\n const processScroll = () => {\n pendingRef.scheduled = false;\n try {\n // Note: We delegate root/groups container positioning to syncSpritesToViewport\n // because it encapsulates the logic for conditional vertical alignment (offsetY)\n // in different view modes. Manually setting position here would overwrite that logic.\n\n syncScrollSprites(\n {\n root: rootRef.current,\n groupsContainer: groupsContainerRef.current,\n container: parentContainerRef.current,\n sprites: spritesRef.current,\n layout,\n visibleIds,\n items,\n cardWidth,\n cardHeight,\n panX,\n panY,\n zoomLevel,\n viewportWidth,\n viewportHeight,\n createCardSprite: (id: string | number, x: number, y: number) =>\n createCardSpriteExternal(\n id,\n x,\n y,\n items as TItem[],\n (item, e, id) => onCardClickRef.current(item, e, id),\n (e) => onPanStartRef.current(asReactMouseEvent(e)),\n cardWidth,\n cardHeight,\n cardColorsRef.current,\n cardRenderer,\n resolveId,\n ),\n updateCardContent: (sprite: CardSprite, item: TItem) =>\n updateCardContentExternal(\n sprite,\n item,\n selectedId,\n cardWidth,\n cardHeight,\n cardColorsRef.current,\n cardRenderer,\n ),\n isViewTransition: isViewTransitionRef.current,\n viewMode,\n transitionSeenIds: transitionSeenIdsRef.current,\n prevScrollTop: prevScrollTopRef.current,\n prevScrollLeft: prevScrollLeftRef.current,\n },\n transitionLayoutRef.current,\n );\n\n // Update previous scroll position for next frame\n prevScrollTopRef.current = container.scrollTop || 0;\n prevScrollLeftRef.current = container.scrollLeft || 0;\n needsRenderRef.current = true;\n app.renderer?.render(app.stage);\n } catch (e) {\n console.error('[PivotCanvas] processScroll error', e);\n }\n };\n\n const onScroll = () => {\n // schedule the work for the next animation frame\n if (!pendingRef.scheduled) {\n pendingRef.scheduled = true;\n requestAnimationFrame(processScroll);\n }\n };\n\n container.addEventListener('scroll', onScroll, { passive: true });\n\n return () => {\n container.removeEventListener('scroll', onScroll);\n };\n }, [\n pixiReady,\n layout,\n visibleIds,\n items,\n cardWidth,\n cardHeight,\n zoomLevel,\n viewportWidth,\n viewportHeight,\n panX,\n panY,\n grouping,\n viewMode,\n selectedId,\n onCardClick,\n onPanStart,\n appRef,\n cardColorsRef,\n groupsContainerRef,\n isViewTransitionRef,\n needsRenderRef,\n onCardClickRef,\n onPanStartRef,\n parentContainerRef,\n prevScrollLeftRef,\n prevScrollTopRef,\n rootRef,\n spritesRef,\n transitionLayoutRef,\n transitionSeenIdsRef,\n ]);\n};\n"],"names":["createCardSpriteExternal","updateCardContentExternal"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"usePivotScrollSync.js","sources":["../../../../../PivotViewer/components/pivot/usePivotScrollSync.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { useEffect } from 'react';\nimport { asReactMouseEvent } from './asReactMouseEvent';\nimport type { CardSprite } from './constants';\nimport {\n createCardSprite as createCardSpriteExternal,\n updateCardContent as updateCardContentExternal,\n} from './sprites';\nimport { syncScrollSprites } from './syncScrollSprites';\nimport type { PivotRenderContext } from './PivotRenderContext';\n\n/**\n * Syncs the card sprites once per animation frame while the viewport scrolls, natively or\n * programmatically.\n * @param context The props, stage, transition state and colors.\n */\nexport const usePivotScrollSync = <TItem extends object>({\n props,\n stage,\n transition,\n cardColorsRef,\n onCardClickRef,\n onPanStartRef,\n}: PivotRenderContext<TItem>) => {\n const {\n items,\n layout,\n grouping,\n visibleIds,\n cardWidth,\n cardHeight,\n zoomLevel,\n panX,\n panY,\n viewportWidth,\n viewportHeight,\n selectedId,\n viewMode,\n cardRenderer,\n resolveId,\n onPanStart,\n onCardClick,\n containerRef: parentContainerRef,\n } = props;\n const { rootRef, groupsContainerRef, spritesRef, appRef, needsRenderRef, pixiReady } =\n stage;\n const {\n isViewTransitionRef,\n transitionLayoutRef,\n transitionSeenIdsRef,\n prevScrollTopRef,\n prevScrollLeftRef,\n } = transition;\n\n // Listen to native scroll events on the parent container so we update the\n // Pixi world immediately when the user scrolls (native scrollbar or\n // programmatic). This ensures `syncSpritesToViewport` runs on scroll and\n // creates/destroys sprites as the viewport moves.\n useEffect(() => {\n if (\n !pixiReady ||\n !parentContainerRef ||\n !parentContainerRef.current ||\n !appRef.current ||\n !rootRef.current\n )\n return;\n\n const container = parentContainerRef.current;\n const app = appRef.current;\n\n // rAF-batched scroll handling: process scroll once per animation frame to avoid heavy synchronous work inside\n // the scroll event which causes jank and de-synchronisation between the\n // compositor and Pixi render updates.\n const pendingRef = { scheduled: false } as { scheduled: boolean };\n let frameHandle = 0;\n\n const processScroll = () => {\n pendingRef.scheduled = false;\n try {\n // Note: We delegate root/groups container positioning to syncSpritesToViewport\n // because it encapsulates the logic for conditional vertical alignment (offsetY)\n // in different view modes. Manually setting position here would overwrite that logic.\n\n const { pending } = syncScrollSprites(\n {\n root: rootRef.current,\n groupsContainer: groupsContainerRef.current,\n container: parentContainerRef.current,\n sprites: spritesRef.current,\n layout,\n visibleIds,\n items,\n cardWidth,\n cardHeight,\n panX,\n panY,\n zoomLevel,\n viewportWidth,\n viewportHeight,\n createCardSprite: (id: string | number, x: number, y: number) =>\n createCardSpriteExternal(\n id,\n x,\n y,\n items as TItem[],\n (item, e, id) => onCardClickRef.current(item, e, id),\n (e) => onPanStartRef.current(asReactMouseEvent(e)),\n cardWidth,\n cardHeight,\n cardColorsRef.current,\n cardRenderer,\n resolveId,\n ),\n updateCardContent: (sprite: CardSprite, item: TItem) =>\n updateCardContentExternal(\n sprite,\n item,\n selectedId,\n cardWidth,\n cardHeight,\n cardColorsRef.current,\n cardRenderer,\n ),\n isViewTransition: isViewTransitionRef.current,\n viewMode,\n transitionSeenIds: transitionSeenIdsRef.current,\n prevScrollTop: prevScrollTopRef.current,\n prevScrollLeft: prevScrollLeftRef.current,\n },\n transitionLayoutRef.current,\n );\n\n // Update previous scroll position for next frame\n prevScrollTopRef.current = container.scrollTop || 0;\n prevScrollLeftRef.current = container.scrollLeft || 0;\n needsRenderRef.current = true;\n app.renderer?.render(app.stage);\n\n // Creation was deferred by the per-frame budget: continue on the next frame\n // until the buffer is filled.\n if (pending) {\n pendingRef.scheduled = true;\n frameHandle = requestAnimationFrame(processScroll);\n }\n } catch (e) {\n console.error('[PivotCanvas] processScroll error', e);\n }\n };\n\n const onScroll = () => {\n // schedule the work for the next animation frame\n if (!pendingRef.scheduled) {\n pendingRef.scheduled = true;\n frameHandle = requestAnimationFrame(processScroll);\n }\n };\n\n container.addEventListener('scroll', onScroll, { passive: true });\n\n return () => {\n container.removeEventListener('scroll', onScroll);\n cancelAnimationFrame(frameHandle);\n };\n }, [\n pixiReady,\n layout,\n visibleIds,\n items,\n cardWidth,\n cardHeight,\n zoomLevel,\n viewportWidth,\n viewportHeight,\n panX,\n panY,\n grouping,\n viewMode,\n selectedId,\n onCardClick,\n onPanStart,\n appRef,\n cardColorsRef,\n groupsContainerRef,\n isViewTransitionRef,\n needsRenderRef,\n onCardClickRef,\n onPanStartRef,\n parentContainerRef,\n prevScrollLeftRef,\n prevScrollTopRef,\n rootRef,\n spritesRef,\n transitionLayoutRef,\n transitionSeenIdsRef,\n ]);\n};\n"],"names":["createCardSpriteExternal","updateCardContentExternal"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePivotSpriteSync.d.ts","sourceRoot":"","sources":["../../../../../PivotViewer/components/pivot/usePivotSpriteSync.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAsB,CAAC;AAE/D;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAAI,KAAK,SAAS,MAAM,+EAOpD,kBAAkB,CAAC,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"usePivotSpriteSync.d.ts","sourceRoot":"","sources":["../../../../../PivotViewer/components/pivot/usePivotSpriteSync.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAsB,CAAC;AAE/D;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAAI,KAAK,SAAS,MAAM,+EAOpD,kBAAkB,CAAC,KAAK,CAAC,SAkO3B,CAAC"}
|
|
@@ -1,13 +1,40 @@
|
|
|
1
|
-
import { useEffect } from 'react';
|
|
1
|
+
import { useRef, useEffect } from 'react';
|
|
2
2
|
import { startAnimationLoop } from './animation.js';
|
|
3
3
|
import { asReactMouseEvent } from './asReactMouseEvent.js';
|
|
4
4
|
import { updateCardContent, createCardSprite } from './sprites.js';
|
|
5
|
-
import { syncSpritesToViewport } from './visibility.js';
|
|
5
|
+
import { syncSpritesToViewport, createTransitionCompleteSync } from './visibility.js';
|
|
6
6
|
|
|
7
7
|
const usePivotSpriteSync = ({ props, stage, transition, cardColorsRef, colorRevision, onCardClickRef, }) => {
|
|
8
8
|
const { items, layout, grouping, visibleIds, cardWidth, cardHeight, zoomLevel, panX, panY, viewportWidth, viewportHeight, selectedId, viewMode, cardRenderer, colorOverrides, resolveId, onPanStart, containerRef: parentContainerRef, } = props;
|
|
9
9
|
const { rootRef, groupsContainerRef, spritesRef, appRef, animationFrameRef, mountedRef, needsRenderRef, pixiReady, } = stage;
|
|
10
10
|
const { isAnimatingRef, isViewTransitionRef, lastViewChangeTimeRef, previousViewModeRef, prevLayoutRef, transitionLayoutRef, transitionSeenIdsRef, prevGroupingRef, prevScrollTopRef, prevScrollLeftRef, prevPanRef, } = transition;
|
|
11
|
+
const buildSyncParamsRef = useRef(null);
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
buildSyncParamsRef.current = () => {
|
|
14
|
+
return {
|
|
15
|
+
root: rootRef.current,
|
|
16
|
+
groupsContainer: groupsContainerRef.current,
|
|
17
|
+
container: parentContainerRef.current,
|
|
18
|
+
sprites: spritesRef.current,
|
|
19
|
+
layout,
|
|
20
|
+
visibleIds,
|
|
21
|
+
items,
|
|
22
|
+
cardWidth,
|
|
23
|
+
cardHeight,
|
|
24
|
+
panX,
|
|
25
|
+
panY,
|
|
26
|
+
zoomLevel,
|
|
27
|
+
viewportWidth,
|
|
28
|
+
viewportHeight,
|
|
29
|
+
viewMode,
|
|
30
|
+
createCardSprite: (id, x, y) => createCardSprite(id, x, y, items, (item, e, id) => onCardClickRef.current(item, e, id), (e) => onPanStart(asReactMouseEvent(e)), cardWidth, cardHeight, cardColorsRef.current, cardRenderer, resolveId),
|
|
31
|
+
updateCardContent: (sprite, item) => updateCardContent(sprite, item, selectedId, cardWidth, cardHeight, cardColorsRef.current, cardRenderer),
|
|
32
|
+
transitionSeenIds: transitionSeenIdsRef.current,
|
|
33
|
+
prevScrollTop: prevScrollTopRef.current,
|
|
34
|
+
prevScrollLeft: prevScrollLeftRef.current,
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
});
|
|
11
38
|
useEffect(() => {
|
|
12
39
|
if (!rootRef.current || !parentContainerRef.current || !pixiReady) {
|
|
13
40
|
return;
|
|
@@ -30,32 +57,13 @@ const usePivotSpriteSync = ({ props, stage, transition, cardColorsRef, colorRevi
|
|
|
30
57
|
const currentScrollTop = parentContainerRef.current?.scrollTop || 0;
|
|
31
58
|
const currentScrollLeft = parentContainerRef.current?.scrollLeft || 0;
|
|
32
59
|
const syncParams = {
|
|
33
|
-
|
|
34
|
-
groupsContainer: groupsContainerRef.current,
|
|
35
|
-
container: parentContainerRef.current,
|
|
36
|
-
sprites: spritesRef.current,
|
|
37
|
-
layout,
|
|
38
|
-
visibleIds,
|
|
39
|
-
items,
|
|
40
|
-
cardWidth,
|
|
41
|
-
cardHeight,
|
|
42
|
-
panX,
|
|
43
|
-
panY,
|
|
60
|
+
...buildSyncParamsRef.current(),
|
|
44
61
|
panDeltaX,
|
|
45
62
|
panDeltaY,
|
|
46
|
-
zoomLevel,
|
|
47
|
-
viewportWidth,
|
|
48
|
-
viewportHeight,
|
|
49
|
-
viewMode,
|
|
50
|
-
createCardSprite: (id, x, y) => createCardSprite(id, x, y, items, (item, e, id) => onCardClickRef.current(item, e, id), (e) => onPanStart(asReactMouseEvent(e)), cardWidth, cardHeight, cardColorsRef.current, cardRenderer, resolveId),
|
|
51
|
-
updateCardContent: (sprite, item) => updateCardContent(sprite, item, selectedId, cardWidth, cardHeight, cardColorsRef.current, cardRenderer),
|
|
52
63
|
isViewTransition: isViewTransitionRef.current,
|
|
53
64
|
prevLayout: prevLayoutRef.current,
|
|
54
|
-
transitionSeenIds: transitionSeenIdsRef.current,
|
|
55
|
-
prevScrollTop: prevScrollTopRef.current,
|
|
56
|
-
prevScrollLeft: prevScrollLeftRef.current,
|
|
57
65
|
};
|
|
58
|
-
syncSpritesToViewport(syncParams);
|
|
66
|
+
const { pending } = syncSpritesToViewport(syncParams);
|
|
59
67
|
prevScrollTopRef.current = currentScrollTop;
|
|
60
68
|
prevScrollLeftRef.current = currentScrollLeft;
|
|
61
69
|
needsRenderRef.current = true;
|
|
@@ -71,13 +79,26 @@ const usePivotSpriteSync = ({ props, stage, transition, cardColorsRef, colorRevi
|
|
|
71
79
|
needsRenderRef,
|
|
72
80
|
spritesRef,
|
|
73
81
|
isViewTransitionRef,
|
|
74
|
-
syncVisibility: () =>
|
|
75
|
-
...syncParams,
|
|
76
|
-
isViewTransition: false,
|
|
77
|
-
sweepImmediately: true,
|
|
78
|
-
}),
|
|
82
|
+
syncVisibility: createTransitionCompleteSync(() => buildSyncParamsRef.current()),
|
|
79
83
|
onTransitionComplete: () => transitionSeenIdsRef.current.clear(),
|
|
80
84
|
});
|
|
85
|
+
let frameHandle = 0;
|
|
86
|
+
const replenish = () => {
|
|
87
|
+
const result = syncSpritesToViewport({
|
|
88
|
+
...syncParams,
|
|
89
|
+
panDeltaX: 0,
|
|
90
|
+
panDeltaY: 0,
|
|
91
|
+
isViewTransition: isViewTransitionRef.current,
|
|
92
|
+
});
|
|
93
|
+
appRef.current?.renderer?.render(appRef.current.stage);
|
|
94
|
+
frameHandle = result.pending ? requestAnimationFrame(replenish) : 0;
|
|
95
|
+
};
|
|
96
|
+
if (pending)
|
|
97
|
+
frameHandle = requestAnimationFrame(replenish);
|
|
98
|
+
return () => {
|
|
99
|
+
if (frameHandle)
|
|
100
|
+
cancelAnimationFrame(frameHandle);
|
|
101
|
+
};
|
|
81
102
|
}, [
|
|
82
103
|
layout,
|
|
83
104
|
visibleIds,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usePivotSpriteSync.js","sources":["../../../../../PivotViewer/components/pivot/usePivotSpriteSync.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { useEffect } from 'react';\nimport { startAnimationLoop as startAnimationLoopExternal } from './animation';\nimport { asReactMouseEvent } from './asReactMouseEvent';\nimport type { CardSprite } from './constants';\nimport {\n createCardSprite as createCardSpriteExternal,\n updateCardContent as updateCardContentExternal,\n} from './sprites';\nimport { syncSpritesToViewport } from './visibility';\nimport type { PivotRenderContext } from './PivotRenderContext';\n\n/**\n * Keeps the card sprites in step with the layout, filter, zoom and pan, starting transitions when the\n * view, grouping or layout changes and running the animation loop.\n * @param context The props, stage, transition state and colors.\n */\nexport const usePivotSpriteSync = <TItem extends object>({\n props,\n stage,\n transition,\n cardColorsRef,\n colorRevision,\n onCardClickRef,\n}: PivotRenderContext<TItem>) => {\n const {\n items,\n layout,\n grouping,\n visibleIds,\n cardWidth,\n cardHeight,\n zoomLevel,\n panX,\n panY,\n viewportWidth,\n viewportHeight,\n selectedId,\n viewMode,\n cardRenderer,\n colorOverrides,\n resolveId,\n onPanStart,\n containerRef: parentContainerRef,\n } = props;\n const {\n rootRef,\n groupsContainerRef,\n spritesRef,\n appRef,\n animationFrameRef,\n mountedRef,\n needsRenderRef,\n pixiReady,\n } = stage;\n const {\n isAnimatingRef,\n isViewTransitionRef,\n lastViewChangeTimeRef,\n previousViewModeRef,\n prevLayoutRef,\n transitionLayoutRef,\n transitionSeenIdsRef,\n prevGroupingRef,\n prevScrollTopRef,\n prevScrollLeftRef,\n prevPanRef,\n } = transition;\n\n useEffect(() => {\n if (!rootRef.current || !parentContainerRef.current || !pixiReady) {\n return;\n }\n\n // Check if this is a view mode change (not just pan/scroll)\n const viewModeChanged = previousViewModeRef.current !== viewMode;\n const groupingChanged = prevGroupingRef.current !== grouping;\n const layoutChanged = prevLayoutRef.current !== layout;\n\n if (viewModeChanged || groupingChanged || layoutChanged) {\n transitionSeenIdsRef.current.clear();\n if (layoutChanged) transitionLayoutRef.current = prevLayoutRef.current;\n isViewTransitionRef.current = true;\n lastViewChangeTimeRef.current = Date.now();\n previousViewModeRef.current = viewMode;\n prevGroupingRef.current = grouping;\n\n // Don't hide sprites here - let visibility.ts handle the transition\n // The syncSpritesToViewport function will properly animate sprites to new positions\n // during view transitions (isViewTransitionRef.current = true), and visibility.ts\n // will handle cleanup of sprites that no longer have positions in the layout.\n // Previously, hiding sprites here caused sorting/transitions to not work because\n // sprites were destroyed before they could animate.\n }\n\n const panDeltaX = panX - prevPanRef.current.x;\n const panDeltaY = panY - prevPanRef.current.y;\n prevPanRef.current = { x: panX, y: panY };\n\n // Sync sprites into viewport and create/remove as needed\n // Provide wrappers for sprite creation and content update so helpers have required context\n const currentScrollTop = parentContainerRef.current?.scrollTop || 0;\n const currentScrollLeft = parentContainerRef.current?.scrollLeft || 0;\n\n const syncParams = {\n root: rootRef.current,\n groupsContainer: groupsContainerRef.current,\n container: parentContainerRef.current,\n sprites: spritesRef.current,\n layout,\n visibleIds,\n items,\n cardWidth,\n cardHeight,\n panX,\n panY,\n panDeltaX,\n panDeltaY,\n zoomLevel,\n viewportWidth,\n viewportHeight,\n viewMode,\n createCardSprite: (id: string | number, x: number, y: number) =>\n createCardSpriteExternal(\n id,\n x,\n y,\n items as TItem[],\n (item: TItem, e: MouseEvent, id: string | number) =>\n onCardClickRef.current(item, e, id),\n (e: MouseEvent) => onPanStart(asReactMouseEvent(e)),\n cardWidth,\n cardHeight,\n cardColorsRef.current,\n cardRenderer,\n resolveId,\n ),\n updateCardContent: (sprite: CardSprite, item: TItem) =>\n updateCardContentExternal(\n sprite,\n item,\n selectedId,\n cardWidth,\n cardHeight,\n cardColorsRef.current,\n cardRenderer,\n ),\n isViewTransition: isViewTransitionRef.current,\n prevLayout: prevLayoutRef.current,\n transitionSeenIds: transitionSeenIdsRef.current,\n prevScrollTop: prevScrollTopRef.current,\n prevScrollLeft: prevScrollLeftRef.current,\n };\n syncSpritesToViewport(syncParams);\n\n // Update previous scroll position for next frame\n prevScrollTopRef.current = currentScrollTop;\n prevScrollLeftRef.current = currentScrollLeft;\n needsRenderRef.current = true;\n\n // Force an immediate render after syncing sprites to ensure cards appear\n if (appRef.current?.renderer && rootRef.current) {\n appRef.current.renderer.render(appRef.current.stage);\n needsRenderRef.current = false;\n }\n\n startAnimationLoopExternal({\n mountedRef,\n appRef,\n animationFrameRef,\n isAnimatingRef,\n needsRenderRef,\n spritesRef,\n isViewTransitionRef,\n syncVisibility: () =>\n syncSpritesToViewport({\n ...syncParams,\n isViewTransition: false,\n sweepImmediately: true,\n }),\n onTransitionComplete: () => transitionSeenIdsRef.current.clear(),\n });\n }, [\n layout,\n visibleIds,\n items,\n cardWidth,\n cardHeight,\n pixiReady,\n zoomLevel,\n panX,\n panY,\n grouping,\n viewMode,\n colorOverrides,\n colorRevision,\n animationFrameRef,\n appRef,\n cardColorsRef,\n groupsContainerRef,\n isAnimatingRef,\n isViewTransitionRef,\n lastViewChangeTimeRef,\n mountedRef,\n needsRenderRef,\n onCardClickRef,\n parentContainerRef,\n prevGroupingRef,\n prevLayoutRef,\n prevPanRef,\n prevScrollLeftRef,\n prevScrollTopRef,\n previousViewModeRef,\n rootRef,\n spritesRef,\n transitionLayoutRef,\n transitionSeenIdsRef,\n ]);\n\n // Update prevLayoutRef after processing layout changes\n useEffect(() => {\n prevLayoutRef.current = layout;\n }, [layout, prevLayoutRef]);\n};\n"],"names":["createCardSpriteExternal","updateCardContentExternal","startAnimationLoopExternal"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"usePivotSpriteSync.js","sources":["../../../../../PivotViewer/components/pivot/usePivotSpriteSync.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport { useEffect, useRef } from 'react';\nimport { startAnimationLoop as startAnimationLoopExternal } from './animation';\nimport { asReactMouseEvent } from './asReactMouseEvent';\nimport type { CardSprite } from './constants';\nimport {\n createCardSprite as createCardSpriteExternal,\n updateCardContent as updateCardContentExternal,\n} from './sprites';\nimport { createTransitionCompleteSync, syncSpritesToViewport, type SyncParams } from './visibility';\nimport type { PivotRenderContext } from './PivotRenderContext';\n\n/**\n * Keeps the card sprites in step with the layout, filter, zoom and pan, starting transitions when the\n * view, grouping or layout changes and running the animation loop.\n * @param context The props, stage, transition state and colors.\n */\nexport const usePivotSpriteSync = <TItem extends object>({\n props,\n stage,\n transition,\n cardColorsRef,\n colorRevision,\n onCardClickRef,\n}: PivotRenderContext<TItem>) => {\n const {\n items,\n layout,\n grouping,\n visibleIds,\n cardWidth,\n cardHeight,\n zoomLevel,\n panX,\n panY,\n viewportWidth,\n viewportHeight,\n selectedId,\n viewMode,\n cardRenderer,\n colorOverrides,\n resolveId,\n onPanStart,\n containerRef: parentContainerRef,\n } = props;\n const {\n rootRef,\n groupsContainerRef,\n spritesRef,\n appRef,\n animationFrameRef,\n mountedRef,\n needsRenderRef,\n pixiReady,\n } = stage;\n const {\n isAnimatingRef,\n isViewTransitionRef,\n lastViewChangeTimeRef,\n previousViewModeRef,\n prevLayoutRef,\n transitionLayoutRef,\n transitionSeenIdsRef,\n prevGroupingRef,\n prevScrollTopRef,\n prevScrollLeftRef,\n prevPanRef,\n } = transition;\n\n // Always holds a builder for the sync parameters of the latest render. It is refreshed before\n // the sync effect below runs, so deferred callbacks never see stale layout, zoom or items.\n const buildSyncParamsRef = useRef<(() => SyncParams<TItem>) | null>(null);\n useEffect(() => {\n buildSyncParamsRef.current = (): SyncParams<TItem> => {\n return {\n root: rootRef.current,\n groupsContainer: groupsContainerRef.current,\n container: parentContainerRef.current,\n sprites: spritesRef.current,\n layout,\n visibleIds,\n items,\n cardWidth,\n cardHeight,\n panX,\n panY,\n zoomLevel,\n viewportWidth,\n viewportHeight,\n viewMode,\n createCardSprite: (id: string | number, x: number, y: number) =>\n createCardSpriteExternal(\n id,\n x,\n y,\n items as TItem[],\n (item: TItem, e: MouseEvent, id: string | number) =>\n onCardClickRef.current(item, e, id),\n (e: MouseEvent) => onPanStart(asReactMouseEvent(e)),\n cardWidth,\n cardHeight,\n cardColorsRef.current,\n cardRenderer,\n resolveId,\n ),\n updateCardContent: (sprite: CardSprite, item: TItem) =>\n updateCardContentExternal(\n sprite,\n item,\n selectedId,\n cardWidth,\n cardHeight,\n cardColorsRef.current,\n cardRenderer,\n ),\n transitionSeenIds: transitionSeenIdsRef.current,\n prevScrollTop: prevScrollTopRef.current,\n prevScrollLeft: prevScrollLeftRef.current,\n };\n };\n });\n\n useEffect(() => {\n if (!rootRef.current || !parentContainerRef.current || !pixiReady) {\n return;\n }\n\n // Check if this is a view mode change (not just pan/scroll)\n const viewModeChanged = previousViewModeRef.current !== viewMode;\n const groupingChanged = prevGroupingRef.current !== grouping;\n const layoutChanged = prevLayoutRef.current !== layout;\n\n if (viewModeChanged || groupingChanged || layoutChanged) {\n transitionSeenIdsRef.current.clear();\n if (layoutChanged) transitionLayoutRef.current = prevLayoutRef.current;\n isViewTransitionRef.current = true;\n lastViewChangeTimeRef.current = Date.now();\n previousViewModeRef.current = viewMode;\n prevGroupingRef.current = grouping;\n\n // Don't hide sprites here - let visibility.ts handle the transition\n // The syncSpritesToViewport function will properly animate sprites to new positions\n // during view transitions (isViewTransitionRef.current = true), and visibility.ts\n // will handle cleanup of sprites that no longer have positions in the layout.\n // Previously, hiding sprites here caused sorting/transitions to not work because\n // sprites were destroyed before they could animate.\n }\n\n const panDeltaX = panX - prevPanRef.current.x;\n const panDeltaY = panY - prevPanRef.current.y;\n prevPanRef.current = { x: panX, y: panY };\n\n // Sync sprites into viewport and create/remove as needed\n // Provide wrappers for sprite creation and content update so helpers have required context\n const currentScrollTop = parentContainerRef.current?.scrollTop || 0;\n const currentScrollLeft = parentContainerRef.current?.scrollLeft || 0;\n\n const syncParams: SyncParams<TItem> = {\n ...buildSyncParamsRef.current!(),\n panDeltaX,\n panDeltaY,\n isViewTransition: isViewTransitionRef.current,\n prevLayout: prevLayoutRef.current,\n };\n const { pending } = syncSpritesToViewport(syncParams);\n\n // Update previous scroll position for next frame\n prevScrollTopRef.current = currentScrollTop;\n prevScrollLeftRef.current = currentScrollLeft;\n needsRenderRef.current = true;\n\n // Force an immediate render after syncing sprites to ensure cards appear\n if (appRef.current?.renderer && rootRef.current) {\n appRef.current.renderer.render(appRef.current.stage);\n needsRenderRef.current = false;\n }\n\n startAnimationLoopExternal({\n mountedRef,\n appRef,\n animationFrameRef,\n isAnimatingRef,\n needsRenderRef,\n spritesRef,\n isViewTransitionRef,\n // Read the current layout, zoom and items when the transition completes, not the\n // values captured when it started.\n syncVisibility: createTransitionCompleteSync(() => buildSyncParamsRef.current!()),\n onTransitionComplete: () => transitionSeenIdsRef.current.clear(),\n });\n\n // Creation was deferred by the per-frame budget: continue on the next frame until\n // the buffer is filled.\n let frameHandle = 0;\n const replenish = () => {\n const result = syncSpritesToViewport({\n ...syncParams,\n panDeltaX: 0,\n panDeltaY: 0,\n isViewTransition: isViewTransitionRef.current,\n });\n appRef.current?.renderer?.render(appRef.current.stage);\n frameHandle = result.pending ? requestAnimationFrame(replenish) : 0;\n };\n if (pending) frameHandle = requestAnimationFrame(replenish);\n\n return () => {\n if (frameHandle) cancelAnimationFrame(frameHandle);\n };\n }, [\n layout,\n visibleIds,\n items,\n cardWidth,\n cardHeight,\n pixiReady,\n zoomLevel,\n panX,\n panY,\n grouping,\n viewMode,\n colorOverrides,\n colorRevision,\n animationFrameRef,\n appRef,\n cardColorsRef,\n groupsContainerRef,\n isAnimatingRef,\n isViewTransitionRef,\n lastViewChangeTimeRef,\n mountedRef,\n needsRenderRef,\n onCardClickRef,\n parentContainerRef,\n prevGroupingRef,\n prevLayoutRef,\n prevPanRef,\n prevScrollLeftRef,\n prevScrollTopRef,\n previousViewModeRef,\n rootRef,\n spritesRef,\n transitionLayoutRef,\n transitionSeenIdsRef,\n ]);\n\n // Update prevLayoutRef after processing layout changes\n useEffect(() => {\n prevLayoutRef.current = layout;\n }, [layout, prevLayoutRef]);\n};\n"],"names":["createCardSpriteExternal","updateCardContentExternal","startAnimationLoopExternal"],"mappings":"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"}
|
|
@@ -28,5 +28,15 @@ export interface SyncParams<TItem> {
|
|
|
28
28
|
prevScrollTop?: number;
|
|
29
29
|
prevScrollLeft?: number;
|
|
30
30
|
}
|
|
31
|
-
export
|
|
31
|
+
export interface SyncResult {
|
|
32
|
+
/** True when sprite creation was deferred to respect the per-frame budget; sync again on the next frame. */
|
|
33
|
+
pending: boolean;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Creates the sync used when a transition completes. Parameters are read when the sync runs, so a
|
|
37
|
+
* layout, zoom or item change since the transition started is honored and on-screen cards survive the sweep.
|
|
38
|
+
* @param getParams Returns the current sync parameters.
|
|
39
|
+
*/
|
|
40
|
+
export declare function createTransitionCompleteSync<TItem>(getParams: () => SyncParams<TItem>): () => void;
|
|
41
|
+
export declare function syncSpritesToViewport<TItem>(params: SyncParams<TItem>): SyncResult;
|
|
32
42
|
//# sourceMappingURL=visibility.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"visibility.d.ts","sourceRoot":"","sources":["../../../../../PivotViewer/components/pivot/visibility.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,IAAI,MAAM,SAAS,CAAC;AAChC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAa,CAAC;AAE9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAoB,CAAC;AAGvD,MAAM,WAAW,UAAU,CAAC,KAAK;IAC7B,IAAI,EAAE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;IAC5B,eAAe,CAAC,EAAE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;IACxC,SAAS,EAAE,cAAc,GAAG,IAAI,CAAC;IACjC,OAAO,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,EAAE,UAAU,CAAC,CAAC;IAC1C,MAAM,EAAE,YAAY,CAAC;IACrB,UAAU,EAAE,WAAW,CAAC;IACxB,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,UAAU,CAAC;IAC5E,iBAAiB,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,KAAK,IAAI,CAAC;IAC7D,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IACjC,iBAAiB,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IACxC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC,
|
|
1
|
+
{"version":3,"file":"visibility.d.ts","sourceRoot":"","sources":["../../../../../PivotViewer/components/pivot/visibility.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,IAAI,MAAM,SAAS,CAAC;AAChC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAa,CAAC;AAE9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAoB,CAAC;AAGvD,MAAM,WAAW,UAAU,CAAC,KAAK;IAC7B,IAAI,EAAE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;IAC5B,eAAe,CAAC,EAAE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;IACxC,SAAS,EAAE,cAAc,GAAG,IAAI,CAAC;IACjC,OAAO,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,EAAE,UAAU,CAAC,CAAC;IAC1C,MAAM,EAAE,YAAY,CAAC;IACrB,UAAU,EAAE,WAAW,CAAC;IACxB,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,UAAU,CAAC;IAC5E,iBAAiB,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,KAAK,IAAI,CAAC;IAC7D,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IACjC,iBAAiB,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC;IACxC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACvB,4GAA4G;IAC5G,OAAO,EAAE,OAAO,CAAC;CACpB;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC,KAAK,CAAC,cAIrF;AAiED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC,GAAG,UAAU,CAkTlF"}
|
|
@@ -1,10 +1,47 @@
|
|
|
1
1
|
import { CARD_GAP } from './constants.js';
|
|
2
2
|
import { destroySprite } from './sprites.js';
|
|
3
3
|
|
|
4
|
+
function createTransitionCompleteSync(getParams) {
|
|
5
|
+
return () => {
|
|
6
|
+
syncSpritesToViewport({ ...getParams(), isViewTransition: false, sweepImmediately: true });
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
function createVisibleRect(source) {
|
|
10
|
+
return {
|
|
11
|
+
left: source.panWorldX,
|
|
12
|
+
right: source.panWorldX + source.worldWidth,
|
|
13
|
+
top: source.panWorldY,
|
|
14
|
+
bottom: source.panWorldY + source.worldHeight,
|
|
15
|
+
epsilon: Math.max(0.5, 0.5 * source.invScale),
|
|
16
|
+
cardWidth: source.cardWidth,
|
|
17
|
+
cardHeight: source.cardHeight,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function rectIntersects(rect, x, y) {
|
|
21
|
+
return x + rect.cardWidth >= rect.left - rect.epsilon &&
|
|
22
|
+
x <= rect.right + rect.epsilon &&
|
|
23
|
+
y + rect.cardHeight >= rect.top - rect.epsilon &&
|
|
24
|
+
y <= rect.bottom + rect.epsilon;
|
|
25
|
+
}
|
|
26
|
+
function sweepableHiddenAt(sprite, position, rect) {
|
|
27
|
+
if (position && rectIntersects(rect, position.x, position.y))
|
|
28
|
+
return undefined;
|
|
29
|
+
return sprite.__lastHiddenAt;
|
|
30
|
+
}
|
|
31
|
+
function tryConsumeCreationBudget(budget, isVisible) {
|
|
32
|
+
if (isVisible)
|
|
33
|
+
return true;
|
|
34
|
+
if (budget.created >= budget.max) {
|
|
35
|
+
budget.pending = true;
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
budget.created++;
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
4
41
|
function syncSpritesToViewport(params) {
|
|
5
42
|
const { root, groupsContainer, container, sprites, layout, visibleIds: _visibleIds, items, cardWidth, cardHeight, panX, panY, panDeltaX, panDeltaY, viewportWidth, viewportHeight, createCardSprite, updateCardContent, zoomLevel, isViewTransition, viewMode, prevLayout, transitionSeenIds } = params;
|
|
6
43
|
if (!root || !container)
|
|
7
|
-
return;
|
|
44
|
+
return { pending: false };
|
|
8
45
|
const viewportPxWidth = container.clientWidth || viewportWidth;
|
|
9
46
|
const viewportPxHeight = container.clientHeight || viewportHeight;
|
|
10
47
|
const contentHeightPx = (layout.totalHeight || 0) * zoomLevel;
|
|
@@ -37,6 +74,7 @@ function syncSpritesToViewport(params) {
|
|
|
37
74
|
const viewportRightWorld = panWorldX + viewportWorldWidth + bufferWorld;
|
|
38
75
|
const viewportTopWorld = panWorldY - bufferWorld;
|
|
39
76
|
const viewportBottomWorld = panWorldY + viewportWorldHeight + bufferWorld;
|
|
77
|
+
const visibleRect = createVisibleRect({ panWorldX, panWorldY, worldWidth: viewportWorldWidth, worldHeight: viewportWorldHeight, invScale, cardWidth, cardHeight });
|
|
40
78
|
const inViewportIds = [];
|
|
41
79
|
const worldEpsilon = Math.max(0.5, 0.5 * invScale);
|
|
42
80
|
const intersectsViewport = (x, y) => x + cardWidth >= viewportLeftWorld - worldEpsilon &&
|
|
@@ -119,7 +157,7 @@ function syncSpritesToViewport(params) {
|
|
|
119
157
|
const SWEEP_MS = 100;
|
|
120
158
|
const now = Date.now();
|
|
121
159
|
for (const [id, sprite] of sprites) {
|
|
122
|
-
const lastHidden = sprite.
|
|
160
|
+
const lastHidden = sweepableHiddenAt(sprite, layout.positions.get(id), visibleRect);
|
|
123
161
|
if (lastHidden && (params.sweepImmediately || now - lastHidden > SWEEP_MS)) {
|
|
124
162
|
try {
|
|
125
163
|
if (sprite.container && sprite.container.parent)
|
|
@@ -141,7 +179,7 @@ function syncSpritesToViewport(params) {
|
|
|
141
179
|
catch (e) {
|
|
142
180
|
}
|
|
143
181
|
const MAX_SPRITES_PER_FRAME = 50;
|
|
144
|
-
|
|
182
|
+
const budget = { created: 0, pending: false, max: MAX_SPRITES_PER_FRAME };
|
|
145
183
|
for (const id of inViewportIds) {
|
|
146
184
|
const position = layout.positions.get(id);
|
|
147
185
|
if (!position) {
|
|
@@ -149,10 +187,9 @@ function syncSpritesToViewport(params) {
|
|
|
149
187
|
}
|
|
150
188
|
let sprite = sprites.get(id);
|
|
151
189
|
if (!sprite) {
|
|
152
|
-
if (
|
|
190
|
+
if (!tryConsumeCreationBudget(budget, rectIntersects(visibleRect, position.x, position.y))) {
|
|
153
191
|
continue;
|
|
154
192
|
}
|
|
155
|
-
createdCount++;
|
|
156
193
|
let startX = position.x;
|
|
157
194
|
let startY = position.y;
|
|
158
195
|
let shouldAnimate = false;
|
|
@@ -213,7 +250,8 @@ function syncSpritesToViewport(params) {
|
|
|
213
250
|
updateCardContent(sprite, item);
|
|
214
251
|
}
|
|
215
252
|
}
|
|
253
|
+
return { pending: budget.pending };
|
|
216
254
|
}
|
|
217
255
|
|
|
218
|
-
export { syncSpritesToViewport };
|
|
256
|
+
export { createTransitionCompleteSync, syncSpritesToViewport };
|
|
219
257
|
//# sourceMappingURL=visibility.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"visibility.js","sources":["../../../../../PivotViewer/components/pivot/visibility.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport * as PIXI from 'pixi.js';\nimport type { CardSprite } from './constants';\nimport { CARD_GAP } from './constants';\nimport type { LayoutResult } from '../../engine/types';\nimport { destroySprite } from './sprites';\n\nexport interface SyncParams<TItem> {\n root: PIXI.Container | null;\n groupsContainer?: PIXI.Container | null;\n container: HTMLDivElement | null;\n sprites: Map<string | number, CardSprite>;\n layout: LayoutResult;\n visibleIds: Uint32Array;\n items: TItem[];\n cardWidth: number;\n cardHeight: number;\n panX: number;\n panY: number;\n panDeltaX?: number;\n panDeltaY?: number;\n viewportWidth: number;\n viewportHeight: number;\n zoomLevel: number;\n createCardSprite: (id: string | number, x: number, y: number) => CardSprite;\n updateCardContent: (sprite: CardSprite, item: TItem) => void;\n isViewTransition?: boolean;\n viewMode: string;\n prevLayout?: LayoutResult | null;\n transitionSeenIds: Set<string | number>;\n sweepImmediately?: boolean;\n prevScrollTop?: number;\n prevScrollLeft?: number;\n}\n\nexport function syncSpritesToViewport<TItem>(params: SyncParams<TItem>) {\n const { root, groupsContainer, container, sprites, layout, visibleIds: _visibleIds, items, cardWidth, cardHeight, panX, panY, panDeltaX, panDeltaY, viewportWidth, viewportHeight, createCardSprite, updateCardContent, zoomLevel, isViewTransition, viewMode, prevLayout, transitionSeenIds } = params;\n if (!root || !container) return;\n\n void _visibleIds;\n\n // Use the container's measured client size for the viewport dimensions\n // (in pixels). The passed `viewportWidth`/`viewportHeight` can be stale\n // when the browser/device zoom changes; `clientWidth/clientHeight` are\n // authoritative for the actual visible pixel area.\n const viewportPxWidth = container.clientWidth || viewportWidth;\n const viewportPxHeight = container.clientHeight || viewportHeight;\n\n const contentHeightPx = (layout.totalHeight || 0) * zoomLevel;\n let offsetY = 0;\n\n // If content fits vertically within the viewport, align relative to bottom.\n // The spacer ensures container isn't scrollable in this case (scrollTop=0).\n // The items are at large Y coordinates relative to layout.totalHeight.\n // We want the bottom of the layout (totalHeight) to align with viewport bottom.\n if (viewMode === 'grouped' && contentHeightPx < viewportPxHeight) {\n // Calculate offset in pixels to shift the content down\n offsetY = viewportPxHeight - contentHeightPx;\n }\n\n // Use the container's actual scroll position for positioning, not the passed panX/panY\n // which may be stale (from React state) compared to live DOM scroll values.\n const actualScrollX = typeof container.scrollLeft === 'number' ? container.scrollLeft : (panX || 0);\n const actualScrollY = typeof container.scrollTop === 'number' ? container.scrollTop : (panY || 0);\n\n // Apply scaling and position to root container\n if (root) {\n root.scale.set(zoomLevel);\n // Standard position: -scrollX, -scrollY\n // Plus vertical alignment offset if zoomed out\n root.position.set(-actualScrollX, offsetY - actualScrollY);\n }\n \n // Apply synchronization to groups container if present\n if (groupsContainer) {\n groupsContainer.scale.set(zoomLevel);\n groupsContainer.position.set(-actualScrollX, offsetY - actualScrollY);\n }\n\n // `visibleIds` comes from callers but this module iterates `layout.positions`\n\n // Note: Pan delta compensation is NOT applied during view transitions because:\n // 1. The time-based animation system handles position changes smoothly\n // 2. Applying pan delta during animation interferes with the interpolation\n // 3. The scroll position changes are a natural part of the view mode switch\n // This compensation is only useful for rapid scrolling/panning where sprites\n // need to maintain visual stability, which isn't the case during view transitions.\n\n const visibleSet = new Set<string | number>();\n\n // Increase buffer (in world units) to reduce edge cases where rapid\n // scrolling skips sprite creation. Keep buffer in world units and convert\n // DOM pixel measurements into world coordinates below to avoid mixing\n // coordinate spaces which can cause precision drift at browser zooms.\n const baseBufferWorld = Math.max(cardWidth, cardHeight) * 4;\n // Ensure buffer scales with viewport size (in world units) so that when\n // zoomed out we still pre-create enough sprites ahead of the viewport.\n const invScale = zoomLevel && zoomLevel !== 0 ? 1 / zoomLevel : 1;\n // The layout positions are in world units; when the root container is scaled\n // (zoomed) the rendered pixel position = position * zoomLevel. The DOM\n // scroll positions (`container.scrollLeft/Top`) are the authoritative pixel\n // camera offsets; prefer them over the passed `panX/panY` to avoid stale\n // values or race conditions between React state and direct DOM updates.\n const effectivePanX = typeof container.scrollLeft === 'number' ? container.scrollLeft : (panX || 0);\n const effectivePanY = typeof container.scrollTop === 'number' ? container.scrollTop : (panY || 0);\n\n // Convert pixel-based DOM measurements into world units so we compare like\n // with like. root.position is set using -pixels, so the mapping\n // from DOM scroll (pixels) to world units is: world = pixels / zoomLevel.\n // OffsetY is already in pixels and doesn't need scaling in panWorldY calc\n // because panWorldY is used for viewport buffering/culling, which is relative\n // to the \"camera\" position in world space.\n // The camera world Y = (scrollTop - offsetY) / zoomLevel.\n const effectivePanYWithOffset = effectivePanY - offsetY;\n const panWorldX = effectivePanX * invScale;\n const panWorldY = effectivePanYWithOffset * invScale;\n\n const viewportWorldWidth = viewportPxWidth * invScale;\n const viewportWorldHeight = viewportPxHeight * invScale;\n\n // Ensure bufferWorld is calculated from the actual measured viewport\n // in world units (after converting client pixel dims using invScale).\n // Make buffer adaptive to zoom: when zoomed out (invScale > 1) a small\n // pixel scroll maps to a larger world delta, so increase the buffer.\n // Use the larger of width/height to ensure we buffer enough in both directions.\n const bufferWorld = Math.max(baseBufferWorld * invScale, Math.max(viewportWorldWidth, viewportWorldHeight) * 2.0, baseBufferWorld);\n\n // Do not clamp viewport edges to 0 — allow negative top/left values so the\n // visible window correctly follows the scroll even when the buffer is\n // larger than the current scroll offset.\n const viewportLeftWorld = panWorldX - bufferWorld;\n const viewportRightWorld = panWorldX + viewportWorldWidth + bufferWorld;\n const viewportTopWorld = panWorldY - bufferWorld;\n const viewportBottomWorld = panWorldY + viewportWorldHeight + bufferWorld;\n\n const inViewportIds: (string | number)[] = [];\n // Small tolerance in world units to avoid floating-point edge cases when\n // browser/device zoom or high scroll values produce tiny rounding errors.\n const worldEpsilon = Math.max(0.5, 0.5 * invScale);\n const intersectsViewport = (x: number, y: number) =>\n x + cardWidth >= viewportLeftWorld - worldEpsilon &&\n x <= viewportRightWorld + worldEpsilon &&\n y + cardHeight >= viewportTopWorld - worldEpsilon &&\n y <= viewportBottomWorld + worldEpsilon;\n const addVisibleId = (id: string | number) => {\n if (!visibleSet.has(id)) {\n inViewportIds.push(id);\n visibleSet.add(id);\n }\n };\n\n // Target positions are authoritative, but during a transition cards may\n // still be at their old positions while the camera catches up.\n for (const [id, position] of layout.positions) {\n if (position && intersectsViewport(position.x, position.y)) addVisibleId(id);\n }\n if (isViewTransition) {\n for (const [id, position] of prevLayout?.positions ?? []) {\n if (!sprites.has(id) && !transitionSeenIds.has(id) && layout.positions.has(id) && position && intersectsViewport(position.x, position.y)) addVisibleId(id);\n }\n for (const [id, sprite] of sprites) {\n transitionSeenIds.add(id);\n if (layout.positions.has(id) && intersectsViewport(sprite.currentX, sprite.currentY)) addVisibleId(id);\n }\n }\n\n // Ensure last rows are present when the user scrolls near the bottom.\n // Compute slot/row information and force-insert IDs from the last few\n // rows to avoid missing tiles due to rounding/precision at zoom levels.\n try {\n const slotHeight = cardHeight + (CARD_GAP || 8);\n const totalRows = Math.ceil((layout.totalHeight || 0) / slotHeight) || 0;\n // Determine how many rows are visible in the viewport (world units),\n // then prefetch a fraction of that adjusted by zoom (invScale).\n const rowsVisible = Math.max(1, Math.ceil(viewportWorldHeight / slotHeight));\n const prefetchMultiplier = 0.75; // fraction of viewport to prefetch\n const prefetchRows = Math.max(2, Math.ceil(rowsVisible * prefetchMultiplier * Math.max(1, invScale)));\n const lastRowThresholdY = Math.max(0, (totalRows - prefetchRows) * slotHeight);\n for (const [id, position] of layout.positions) {\n if (position.y >= lastRowThresholdY) {\n if (!visibleSet.has(id)) {\n inViewportIds.push(id);\n visibleSet.add(id);\n }\n }\n }\n } catch (e) {\n void e;\n }\n\n // Outside transitions, avoid mass-hiding sprites on a potentially stale viewport calculation.\n const aggressiveCull = !isViewTransition && sprites.size > Math.max(120, Math.ceil(inViewportIds.length * 1.5));\n\n for (const [id, sprite] of sprites) {\n if (!visibleSet.has(id)) {\n if (aggressiveCull) {\n // Keep sprite visible this frame to avoid visual holes\n try { if (sprite.container) sprite.container.visible = true; } catch (e) { void e; }\n continue;\n }\n\n try {\n if (sprite.container) {\n sprite.container.visible = false;\n }\n (sprite as unknown as { __lastHiddenAt?: number }).__lastHiddenAt ??= Date.now();\n } catch (e) {\n void e;\n }\n } else {\n try {\n if (sprite.container) {\n sprite.container.visible = true;\n }\n if ((sprite as unknown as { __lastHiddenAt?: number }).__lastHiddenAt) delete (sprite as unknown as { __lastHiddenAt?: number }).__lastHiddenAt;\n } catch (e) { void e; }\n }\n }\n\n // Sweep: actually destroy sprites that have been hidden longer than threshold\n try {\n const SWEEP_MS = 100; // keep hidden sprites for 100ms before destruction (reduced from 500ms for faster mode transitions)\n const now = Date.now();\n for (const [id, sprite] of sprites) {\n const lastHidden = (sprite as unknown as { __lastHiddenAt?: number }).__lastHiddenAt;\n if (lastHidden && (params.sweepImmediately || now - lastHidden > SWEEP_MS)) {\n try {\n // remove from parent if present\n if (sprite.container && sprite.container.parent) sprite.container.parent.removeChild(sprite.container);\n } catch (e) {\n void e;\n }\n try {\n destroySprite(sprite);\n } catch (e) {\n void e;\n }\n sprites.delete(id);\n }\n }\n } catch (e) {\n void e;\n }\n\n // Limit the number of sprites created per frame to avoid choking the GPU/CPU\n // when scrolling rapidly or zooming out significantly.\n const MAX_SPRITES_PER_FRAME = 50;\n let createdCount = 0;\n\n\n for (const id of inViewportIds) {\n const position = layout.positions.get(id);\n if (!position) {\n continue;\n }\n\n let sprite = sprites.get(id);\n if (!sprite) {\n if (createdCount >= MAX_SPRITES_PER_FRAME) {\n continue;\n }\n createdCount++;\n\n let startX = position.x;\n let startY = position.y;\n let shouldAnimate = false;\n\n // If view transition, try to find old position to fly in from\n if (isViewTransition && prevLayout && prevLayout.positions.has(id)) {\n const oldPos = prevLayout.positions.get(id);\n if (oldPos && intersectsViewport(oldPos.x, oldPos.y)) {\n startX = oldPos.x;\n startY = oldPos.y;\n\n // If we have a pan delta (camera jump), we need to adjust the start position\n // so that the sprite appears at the same visual location relative to the NEW camera.\n // StartWorld = OldWorld + PanDelta\n if (panDeltaX || panDeltaY) {\n const dx = (panDeltaX || 0) / (zoomLevel || 1);\n const dy = (panDeltaY || 0) / (zoomLevel || 1);\n startX += dx;\n startY += dy;\n }\n\n shouldAnimate = true;\n }\n }\n\n sprite = createCardSprite(id, startX, startY);\n sprites.set(id, sprite);\n if (isViewTransition) transitionSeenIds.add(id);\n if (sprite.container) {\n root.addChild(sprite.container);\n sprite.currentX = startX;\n sprite.currentY = startY;\n // Keep sprite.container positioned in world units; animation/update\n // loop will apply root.scale/position to convert to pixels.\n sprite.container.position.set(startX, startY);\n }\n\n if (shouldAnimate) {\n sprite.targetX = position.x;\n sprite.targetY = position.y;\n sprite.startX = startX;\n sprite.startY = startY;\n sprite.animationStartTime = Date.now();\n sprite.animationDelay = Math.random() * 300;\n }\n }\n\n // Check if target changed to trigger animation\n const targetChanged = sprite.targetX !== position.x || sprite.targetY !== position.y;\n if (targetChanged) {\n if (isViewTransition) {\n // Only set up animation if not already animating - don't reset animation\n // when targets change during layout recalculations\n if (sprite.animationStartTime === undefined) {\n sprite.startX = sprite.currentX;\n sprite.startY = sprite.currentY;\n sprite.animationStartTime = Date.now();\n // Add random delay for \"organic\" fly effect\n sprite.animationDelay = Math.random() * 300;\n }\n // Always update target to the new position (animation will smoothly\n // adjust to the new target)\n sprite.targetX = position.x;\n sprite.targetY = position.y;\n } else {\n sprite.targetX = position.x;\n sprite.targetY = position.y;\n delete sprite.animationStartTime;\n delete sprite.animationDelay;\n }\n }\n\n const item = items[Number(id)];\n if (item) {\n updateCardContent(sprite, item);\n }\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"visibility.js","sources":["../../../../../PivotViewer/components/pivot/visibility.ts"],"sourcesContent":["// Copyright (c) Cratis. All rights reserved.\n// Licensed under the MIT license. See LICENSE file in the project root for full license information.\n\nimport * as PIXI from 'pixi.js';\nimport type { CardSprite } from './constants';\nimport { CARD_GAP } from './constants';\nimport type { LayoutResult } from '../../engine/types';\nimport { destroySprite } from './sprites';\n\nexport interface SyncParams<TItem> {\n root: PIXI.Container | null;\n groupsContainer?: PIXI.Container | null;\n container: HTMLDivElement | null;\n sprites: Map<string | number, CardSprite>;\n layout: LayoutResult;\n visibleIds: Uint32Array;\n items: TItem[];\n cardWidth: number;\n cardHeight: number;\n panX: number;\n panY: number;\n panDeltaX?: number;\n panDeltaY?: number;\n viewportWidth: number;\n viewportHeight: number;\n zoomLevel: number;\n createCardSprite: (id: string | number, x: number, y: number) => CardSprite;\n updateCardContent: (sprite: CardSprite, item: TItem) => void;\n isViewTransition?: boolean;\n viewMode: string;\n prevLayout?: LayoutResult | null;\n transitionSeenIds: Set<string | number>;\n sweepImmediately?: boolean;\n prevScrollTop?: number;\n prevScrollLeft?: number;\n}\n\nexport interface SyncResult {\n /** True when sprite creation was deferred to respect the per-frame budget; sync again on the next frame. */\n pending: boolean;\n}\n\n/**\n * Creates the sync used when a transition completes. Parameters are read when the sync runs, so a\n * layout, zoom or item change since the transition started is honored and on-screen cards survive the sweep.\n * @param getParams Returns the current sync parameters.\n */\nexport function createTransitionCompleteSync<TItem>(getParams: () => SyncParams<TItem>) {\n return () => {\n syncSpritesToViewport({ ...getParams(), isViewTransition: false, sweepImmediately: true });\n };\n}\n\ninterface VisibleRect {\n left: number;\n right: number;\n top: number;\n bottom: number;\n epsilon: number;\n cardWidth: number;\n cardHeight: number;\n}\n\ninterface VisibleRectSource {\n panWorldX: number;\n panWorldY: number;\n worldWidth: number;\n worldHeight: number;\n invScale: number;\n cardWidth: number;\n cardHeight: number;\n}\n\n/**\n * Builds the unbuffered visible rect in world units, with a zoom-aware rounding tolerance. Cards\n * intersecting it are created first and are never subject to the per-frame budget or the sweep.\n */\nfunction createVisibleRect(source: VisibleRectSource): VisibleRect {\n return {\n left: source.panWorldX,\n right: source.panWorldX + source.worldWidth,\n top: source.panWorldY,\n bottom: source.panWorldY + source.worldHeight,\n epsilon: Math.max(0.5, 0.5 * source.invScale),\n cardWidth: source.cardWidth,\n cardHeight: source.cardHeight,\n };\n}\n\nfunction rectIntersects(rect: VisibleRect, x: number, y: number) {\n return x + rect.cardWidth >= rect.left - rect.epsilon &&\n x <= rect.right + rect.epsilon &&\n y + rect.cardHeight >= rect.top - rect.epsilon &&\n y <= rect.bottom + rect.epsilon;\n}\n\n/** When the sprite was hidden, or undefined when it is not hidden or its card is on screen (never swept). */\nfunction sweepableHiddenAt(sprite: CardSprite, position: { x: number; y: number } | undefined, rect: VisibleRect) {\n if (position && rectIntersects(rect, position.x, position.y)) return undefined;\n return (sprite as unknown as { __lastHiddenAt?: number }).__lastHiddenAt;\n}\n\n/**\n * Decides whether a sprite may be created this frame. Visible cards are always allowed;\n * buffer-only cards are limited by the budget and mark the sync as pending when deferred.\n */\nfunction tryConsumeCreationBudget(budget: { created: number; pending: boolean; max: number }, isVisible: boolean) {\n if (isVisible) return true;\n if (budget.created >= budget.max) {\n budget.pending = true;\n return false;\n }\n budget.created++;\n return true;\n}\n\nexport function syncSpritesToViewport<TItem>(params: SyncParams<TItem>): SyncResult {\n const { root, groupsContainer, container, sprites, layout, visibleIds: _visibleIds, items, cardWidth, cardHeight, panX, panY, panDeltaX, panDeltaY, viewportWidth, viewportHeight, createCardSprite, updateCardContent, zoomLevel, isViewTransition, viewMode, prevLayout, transitionSeenIds } = params;\n if (!root || !container) return { pending: false };\n\n void _visibleIds;\n\n // Use the container's measured client size for the viewport dimensions\n // (in pixels). The passed `viewportWidth`/`viewportHeight` can be stale\n // when the browser/device zoom changes; `clientWidth/clientHeight` are\n // authoritative for the actual visible pixel area.\n const viewportPxWidth = container.clientWidth || viewportWidth;\n const viewportPxHeight = container.clientHeight || viewportHeight;\n\n const contentHeightPx = (layout.totalHeight || 0) * zoomLevel;\n let offsetY = 0;\n\n // If content fits vertically within the viewport, align relative to bottom.\n // The spacer ensures container isn't scrollable in this case (scrollTop=0).\n // The items are at large Y coordinates relative to layout.totalHeight.\n // We want the bottom of the layout (totalHeight) to align with viewport bottom.\n if (viewMode === 'grouped' && contentHeightPx < viewportPxHeight) {\n // Calculate offset in pixels to shift the content down\n offsetY = viewportPxHeight - contentHeightPx;\n }\n\n // Use the container's actual scroll position for positioning, not the passed panX/panY\n // which may be stale (from React state) compared to live DOM scroll values.\n const actualScrollX = typeof container.scrollLeft === 'number' ? container.scrollLeft : (panX || 0);\n const actualScrollY = typeof container.scrollTop === 'number' ? container.scrollTop : (panY || 0);\n\n // Apply scaling and position to root container\n if (root) {\n root.scale.set(zoomLevel);\n // Standard position: -scrollX, -scrollY\n // Plus vertical alignment offset if zoomed out\n root.position.set(-actualScrollX, offsetY - actualScrollY);\n }\n \n // Apply synchronization to groups container if present\n if (groupsContainer) {\n groupsContainer.scale.set(zoomLevel);\n groupsContainer.position.set(-actualScrollX, offsetY - actualScrollY);\n }\n\n // `visibleIds` comes from callers but this module iterates `layout.positions`\n\n // Note: Pan delta compensation is NOT applied during view transitions because:\n // 1. The time-based animation system handles position changes smoothly\n // 2. Applying pan delta during animation interferes with the interpolation\n // 3. The scroll position changes are a natural part of the view mode switch\n // This compensation is only useful for rapid scrolling/panning where sprites\n // need to maintain visual stability, which isn't the case during view transitions.\n\n const visibleSet = new Set<string | number>();\n\n // Increase buffer (in world units) to reduce edge cases where rapid\n // scrolling skips sprite creation. Keep buffer in world units and convert\n // DOM pixel measurements into world coordinates below to avoid mixing\n // coordinate spaces which can cause precision drift at browser zooms.\n const baseBufferWorld = Math.max(cardWidth, cardHeight) * 4;\n // Ensure buffer scales with viewport size (in world units) so that when\n // zoomed out we still pre-create enough sprites ahead of the viewport.\n const invScale = zoomLevel && zoomLevel !== 0 ? 1 / zoomLevel : 1;\n // The layout positions are in world units; when the root container is scaled\n // (zoomed) the rendered pixel position = position * zoomLevel. The DOM\n // scroll positions (`container.scrollLeft/Top`) are the authoritative pixel\n // camera offsets; prefer them over the passed `panX/panY` to avoid stale\n // values or race conditions between React state and direct DOM updates.\n const effectivePanX = typeof container.scrollLeft === 'number' ? container.scrollLeft : (panX || 0);\n const effectivePanY = typeof container.scrollTop === 'number' ? container.scrollTop : (panY || 0);\n\n // Convert pixel-based DOM measurements into world units so we compare like\n // with like. root.position is set using -pixels, so the mapping\n // from DOM scroll (pixels) to world units is: world = pixels / zoomLevel.\n // OffsetY is already in pixels and doesn't need scaling in panWorldY calc\n // because panWorldY is used for viewport buffering/culling, which is relative\n // to the \"camera\" position in world space.\n // The camera world Y = (scrollTop - offsetY) / zoomLevel.\n const effectivePanYWithOffset = effectivePanY - offsetY;\n const panWorldX = effectivePanX * invScale;\n const panWorldY = effectivePanYWithOffset * invScale;\n\n const viewportWorldWidth = viewportPxWidth * invScale;\n const viewportWorldHeight = viewportPxHeight * invScale;\n\n // Ensure bufferWorld is calculated from the actual measured viewport\n // in world units (after converting client pixel dims using invScale).\n // Make buffer adaptive to zoom: when zoomed out (invScale > 1) a small\n // pixel scroll maps to a larger world delta, so increase the buffer.\n // Use the larger of width/height to ensure we buffer enough in both directions.\n const bufferWorld = Math.max(baseBufferWorld * invScale, Math.max(viewportWorldWidth, viewportWorldHeight) * 2.0, baseBufferWorld);\n\n // Do not clamp viewport edges to 0 — allow negative top/left values so the\n // visible window correctly follows the scroll even when the buffer is\n // larger than the current scroll offset.\n const viewportLeftWorld = panWorldX - bufferWorld;\n const viewportRightWorld = panWorldX + viewportWorldWidth + bufferWorld;\n const viewportTopWorld = panWorldY - bufferWorld;\n const viewportBottomWorld = panWorldY + viewportWorldHeight + bufferWorld;\n\n const visibleRect = createVisibleRect({ panWorldX, panWorldY, worldWidth: viewportWorldWidth, worldHeight: viewportWorldHeight, invScale, cardWidth, cardHeight });\n\n const inViewportIds: (string | number)[] = [];\n // Small tolerance in world units to avoid floating-point edge cases when\n // browser/device zoom or high scroll values produce tiny rounding errors.\n const worldEpsilon = Math.max(0.5, 0.5 * invScale);\n const intersectsViewport = (x: number, y: number) =>\n x + cardWidth >= viewportLeftWorld - worldEpsilon &&\n x <= viewportRightWorld + worldEpsilon &&\n y + cardHeight >= viewportTopWorld - worldEpsilon &&\n y <= viewportBottomWorld + worldEpsilon;\n const addVisibleId = (id: string | number) => {\n if (!visibleSet.has(id)) {\n inViewportIds.push(id);\n visibleSet.add(id);\n }\n };\n\n // Target positions are authoritative, but during a transition cards may\n // still be at their old positions while the camera catches up.\n for (const [id, position] of layout.positions) {\n if (position && intersectsViewport(position.x, position.y)) addVisibleId(id);\n }\n if (isViewTransition) {\n for (const [id, position] of prevLayout?.positions ?? []) {\n if (!sprites.has(id) && !transitionSeenIds.has(id) && layout.positions.has(id) && position && intersectsViewport(position.x, position.y)) addVisibleId(id);\n }\n for (const [id, sprite] of sprites) {\n transitionSeenIds.add(id);\n if (layout.positions.has(id) && intersectsViewport(sprite.currentX, sprite.currentY)) addVisibleId(id);\n }\n }\n\n // Ensure last rows are present when the user scrolls near the bottom.\n // Compute slot/row information and force-insert IDs from the last few\n // rows to avoid missing tiles due to rounding/precision at zoom levels.\n try {\n const slotHeight = cardHeight + (CARD_GAP || 8);\n const totalRows = Math.ceil((layout.totalHeight || 0) / slotHeight) || 0;\n // Determine how many rows are visible in the viewport (world units),\n // then prefetch a fraction of that adjusted by zoom (invScale).\n const rowsVisible = Math.max(1, Math.ceil(viewportWorldHeight / slotHeight));\n const prefetchMultiplier = 0.75; // fraction of viewport to prefetch\n const prefetchRows = Math.max(2, Math.ceil(rowsVisible * prefetchMultiplier * Math.max(1, invScale)));\n const lastRowThresholdY = Math.max(0, (totalRows - prefetchRows) * slotHeight);\n for (const [id, position] of layout.positions) {\n if (position.y >= lastRowThresholdY) {\n if (!visibleSet.has(id)) {\n inViewportIds.push(id);\n visibleSet.add(id);\n }\n }\n }\n } catch (e) {\n void e;\n }\n\n // Outside transitions, avoid mass-hiding sprites on a potentially stale viewport calculation.\n const aggressiveCull = !isViewTransition && sprites.size > Math.max(120, Math.ceil(inViewportIds.length * 1.5));\n\n for (const [id, sprite] of sprites) {\n if (!visibleSet.has(id)) {\n if (aggressiveCull) {\n // Keep sprite visible this frame to avoid visual holes\n try { if (sprite.container) sprite.container.visible = true; } catch (e) { void e; }\n continue;\n }\n\n try {\n if (sprite.container) {\n sprite.container.visible = false;\n }\n (sprite as unknown as { __lastHiddenAt?: number }).__lastHiddenAt ??= Date.now();\n } catch (e) {\n void e;\n }\n } else {\n try {\n if (sprite.container) {\n sprite.container.visible = true;\n }\n if ((sprite as unknown as { __lastHiddenAt?: number }).__lastHiddenAt) delete (sprite as unknown as { __lastHiddenAt?: number }).__lastHiddenAt;\n } catch (e) { void e; }\n }\n }\n\n // Sweep: actually destroy sprites that have been hidden longer than threshold\n try {\n const SWEEP_MS = 100; // keep hidden sprites for 100ms before destruction (reduced from 500ms for faster mode transitions)\n const now = Date.now();\n for (const [id, sprite] of sprites) {\n const lastHidden = sweepableHiddenAt(sprite, layout.positions.get(id), visibleRect);\n if (lastHidden && (params.sweepImmediately || now - lastHidden > SWEEP_MS)) {\n try {\n // remove from parent if present\n if (sprite.container && sprite.container.parent) sprite.container.parent.removeChild(sprite.container);\n } catch (e) {\n void e;\n }\n try {\n destroySprite(sprite);\n } catch (e) {\n void e;\n }\n sprites.delete(id);\n }\n }\n } catch (e) {\n void e;\n }\n\n // Limit the number of buffer-only sprites created per frame to avoid choking the GPU/CPU\n // when scrolling rapidly or zooming out significantly.\n const MAX_SPRITES_PER_FRAME = 50;\n const budget = { created: 0, pending: false, max: MAX_SPRITES_PER_FRAME };\n\n for (const id of inViewportIds) {\n const position = layout.positions.get(id);\n if (!position) {\n continue;\n }\n\n let sprite = sprites.get(id);\n if (!sprite) {\n if (!tryConsumeCreationBudget(budget, rectIntersects(visibleRect, position.x, position.y))) {\n continue;\n }\n\n let startX = position.x;\n let startY = position.y;\n let shouldAnimate = false;\n\n // If view transition, try to find old position to fly in from\n if (isViewTransition && prevLayout && prevLayout.positions.has(id)) {\n const oldPos = prevLayout.positions.get(id);\n if (oldPos && intersectsViewport(oldPos.x, oldPos.y)) {\n startX = oldPos.x;\n startY = oldPos.y;\n\n // If we have a pan delta (camera jump), we need to adjust the start position\n // so that the sprite appears at the same visual location relative to the NEW camera.\n // StartWorld = OldWorld + PanDelta\n if (panDeltaX || panDeltaY) {\n const dx = (panDeltaX || 0) / (zoomLevel || 1);\n const dy = (panDeltaY || 0) / (zoomLevel || 1);\n startX += dx;\n startY += dy;\n }\n\n shouldAnimate = true;\n }\n }\n\n sprite = createCardSprite(id, startX, startY);\n sprites.set(id, sprite);\n if (isViewTransition) transitionSeenIds.add(id);\n if (sprite.container) {\n root.addChild(sprite.container);\n sprite.currentX = startX;\n sprite.currentY = startY;\n // Keep sprite.container positioned in world units; animation/update\n // loop will apply root.scale/position to convert to pixels.\n sprite.container.position.set(startX, startY);\n }\n\n if (shouldAnimate) {\n sprite.targetX = position.x;\n sprite.targetY = position.y;\n sprite.startX = startX;\n sprite.startY = startY;\n sprite.animationStartTime = Date.now();\n sprite.animationDelay = Math.random() * 300;\n }\n }\n\n // Check if target changed to trigger animation\n const targetChanged = sprite.targetX !== position.x || sprite.targetY !== position.y;\n if (targetChanged) {\n if (isViewTransition) {\n // Only set up animation if not already animating - don't reset animation\n // when targets change during layout recalculations\n if (sprite.animationStartTime === undefined) {\n sprite.startX = sprite.currentX;\n sprite.startY = sprite.currentY;\n sprite.animationStartTime = Date.now();\n // Add random delay for \"organic\" fly effect\n sprite.animationDelay = Math.random() * 300;\n }\n // Always update target to the new position (animation will smoothly\n // adjust to the new target)\n sprite.targetX = position.x;\n sprite.targetY = position.y;\n } else {\n sprite.targetX = position.x;\n sprite.targetY = position.y;\n delete sprite.animationStartTime;\n delete sprite.animationDelay;\n }\n }\n\n const item = items[Number(id)];\n if (item) {\n updateCardContent(sprite, item);\n }\n }\n return { pending: budget.pending };\n}\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED