@cratis/components 0.1.17 → 0.1.19
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/README.md +83 -0
- package/dist/cjs/Common/ErrorBoundary.js +26 -0
- package/dist/cjs/Common/ErrorBoundary.js.map +1 -0
- package/dist/cjs/Common/FormElement.js +10 -0
- package/dist/cjs/Common/FormElement.js.map +1 -0
- package/dist/cjs/Common/index.js +12 -0
- package/dist/cjs/Common/index.js.map +1 -0
- package/dist/cjs/EventModeling/EventModeling.css +146 -0
- package/dist/cjs/EventModeling/EventModeling.js +209 -0
- package/dist/cjs/EventModeling/EventModeling.js.map +1 -0
- package/dist/cjs/EventModeling/components/Canvas.js +403 -0
- package/dist/cjs/EventModeling/components/Canvas.js.map +1 -0
- package/dist/cjs/EventModeling/components/CanvasControls.js +10 -0
- package/dist/cjs/EventModeling/components/CanvasControls.js.map +1 -0
- package/dist/cjs/EventModeling/components/Toolbox.js +18 -0
- package/dist/cjs/EventModeling/components/Toolbox.js.map +1 -0
- package/dist/cjs/EventModeling/engine/connectorGraphics.js +173 -0
- package/dist/cjs/EventModeling/engine/connectorGraphics.js.map +1 -0
- package/dist/cjs/EventModeling/engine/elementSprites.js +301 -0
- package/dist/cjs/EventModeling/engine/elementSprites.js.map +1 -0
- package/dist/cjs/EventModeling/index.js +12 -0
- package/dist/cjs/EventModeling/index.js.map +1 -0
- package/dist/cjs/EventModeling/types.js +60 -0
- package/dist/cjs/EventModeling/types.js.map +1 -0
- package/dist/cjs/PivotViewer/PivotViewer.css +54 -5
- package/dist/cjs/PivotViewer/PivotViewer.js +5 -2
- package/dist/cjs/PivotViewer/PivotViewer.js.map +1 -1
- package/dist/cjs/PivotViewer/components/AxisLabels.js +5 -8
- package/dist/cjs/PivotViewer/components/AxisLabels.js.map +1 -1
- package/dist/cjs/PivotViewer/components/DetailPanel.js +9 -2
- package/dist/cjs/PivotViewer/components/DetailPanel.js.map +1 -1
- package/dist/cjs/PivotViewer/components/PivotCanvas.js +30 -6
- package/dist/cjs/PivotViewer/components/PivotCanvas.js.map +1 -1
- package/dist/cjs/PivotViewer/components/PivotViewerMain.js +16 -5
- package/dist/cjs/PivotViewer/components/PivotViewerMain.js.map +1 -1
- package/dist/cjs/PivotViewer/components/Toolbar.js +34 -2
- package/dist/cjs/PivotViewer/components/Toolbar.js.map +1 -1
- package/dist/cjs/PivotViewer/components/pivot/constants.js +5 -5
- package/dist/cjs/PivotViewer/components/pivot/constants.js.map +1 -1
- package/dist/cjs/PivotViewer/components/pivot/groups.js +15 -15
- package/dist/cjs/PivotViewer/components/pivot/groups.js.map +1 -1
- package/dist/cjs/PivotViewer/components/pivot/sprites.js +10 -27
- package/dist/cjs/PivotViewer/components/pivot/sprites.js.map +1 -1
- package/dist/cjs/PivotViewer/components/pivot/visibility.js +8 -20
- package/dist/cjs/PivotViewer/components/pivot/visibility.js.map +1 -1
- package/dist/cjs/PivotViewer/constants.js +0 -2
- package/dist/cjs/PivotViewer/constants.js.map +1 -1
- package/dist/cjs/PivotViewer/engine/layout.js +1 -1
- package/dist/cjs/PivotViewer/engine/layout.js.map +1 -1
- package/dist/cjs/PivotViewer/hooks/useCardSelection.js +2 -1
- package/dist/cjs/PivotViewer/hooks/useCardSelection.js.map +1 -1
- package/dist/cjs/PivotViewer/hooks/useZoomState.js +4 -0
- package/dist/cjs/PivotViewer/hooks/useZoomState.js.map +1 -1
- package/dist/cjs/PivotViewer/types.js.map +1 -1
- package/dist/cjs/PivotViewer/utils/animations.js +1 -1
- package/dist/cjs/PivotViewer/utils/animations.js.map +1 -1
- package/dist/cjs/PivotViewer/utils/constants.js +1 -1
- package/dist/cjs/PivotViewer/utils/constants.js.map +1 -1
- package/dist/cjs/PivotViewer/utils/selection.js +8 -1
- package/dist/cjs/PivotViewer/utils/selection.js.map +1 -1
- package/dist/cjs/TimeMachine/TimeMachine.js +0 -3
- package/dist/cjs/TimeMachine/TimeMachine.js.map +1 -1
- package/dist/cjs/index.js +16 -12
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/package.json +3 -0
- package/dist/esm/Common/ErrorBoundary.js +7 -4
- package/dist/esm/Common/ErrorBoundary.js.map +1 -1
- package/dist/esm/Common/FormElement.js +7 -4
- package/dist/esm/Common/FormElement.js.map +1 -1
- package/dist/esm/Common/index.js +4 -4
- package/dist/esm/Common/index.js.map +1 -1
- package/dist/esm/EventModeling/EventModeling.css +146 -0
- package/dist/esm/EventModeling/EventModeling.d.ts +11 -0
- package/dist/esm/EventModeling/EventModeling.d.ts.map +1 -0
- package/dist/esm/EventModeling/EventModeling.js +207 -0
- package/dist/esm/EventModeling/EventModeling.js.map +1 -0
- package/dist/esm/EventModeling/EventModeling.stories.d.ts +10 -0
- package/dist/esm/EventModeling/EventModeling.stories.d.ts.map +1 -0
- package/dist/esm/EventModeling/EventModeling.stories.js +252 -0
- package/dist/esm/EventModeling/EventModeling.stories.js.map +1 -0
- package/dist/esm/EventModeling/components/Canvas.d.ts +23 -0
- package/dist/esm/EventModeling/components/Canvas.d.ts.map +1 -0
- package/dist/esm/EventModeling/components/Canvas.js +382 -0
- package/dist/esm/EventModeling/components/Canvas.js.map +1 -0
- package/dist/esm/EventModeling/components/CanvasControls.d.ts +10 -0
- package/dist/esm/EventModeling/components/CanvasControls.d.ts.map +1 -0
- package/dist/esm/EventModeling/components/CanvasControls.js +8 -0
- package/dist/esm/EventModeling/components/CanvasControls.js.map +1 -0
- package/dist/esm/EventModeling/components/Toolbox.d.ts +9 -0
- package/dist/esm/EventModeling/components/Toolbox.d.ts.map +1 -0
- package/dist/esm/EventModeling/components/Toolbox.js +16 -0
- package/dist/esm/EventModeling/components/Toolbox.js.map +1 -0
- package/dist/esm/EventModeling/engine/connectorGraphics.d.ts +12 -0
- package/dist/esm/EventModeling/engine/connectorGraphics.d.ts.map +1 -0
- package/dist/esm/EventModeling/engine/connectorGraphics.js +151 -0
- package/dist/esm/EventModeling/engine/connectorGraphics.js.map +1 -0
- package/dist/esm/EventModeling/engine/elementSprites.d.ts +23 -0
- package/dist/esm/EventModeling/engine/elementSprites.d.ts.map +1 -0
- package/dist/esm/EventModeling/engine/elementSprites.js +276 -0
- package/dist/esm/EventModeling/engine/elementSprites.js.map +1 -0
- package/dist/esm/EventModeling/index.d.ts +3 -0
- package/dist/esm/EventModeling/index.d.ts.map +1 -0
- package/dist/esm/EventModeling/index.js +3 -0
- package/dist/esm/EventModeling/index.js.map +1 -0
- package/dist/esm/EventModeling/types.d.ts +79 -0
- package/dist/esm/EventModeling/types.d.ts.map +1 -0
- package/dist/esm/EventModeling/types.js +56 -0
- package/dist/esm/EventModeling/types.js.map +1 -0
- package/dist/esm/PivotViewer/PivotViewer.css +54 -5
- package/dist/esm/PivotViewer/PivotViewer.d.ts.map +1 -1
- package/dist/esm/PivotViewer/PivotViewer.js +5 -2
- package/dist/esm/PivotViewer/PivotViewer.js.map +1 -1
- package/dist/esm/PivotViewer/PivotViewer.stories.d.ts +0 -1
- package/dist/esm/PivotViewer/PivotViewer.stories.d.ts.map +1 -1
- package/dist/esm/PivotViewer/PivotViewer.stories.js +10 -9
- package/dist/esm/PivotViewer/PivotViewer.stories.js.map +1 -1
- package/dist/esm/PivotViewer/components/AxisLabels.d.ts +2 -1
- package/dist/esm/PivotViewer/components/AxisLabels.d.ts.map +1 -1
- package/dist/esm/PivotViewer/components/AxisLabels.js +6 -9
- package/dist/esm/PivotViewer/components/AxisLabels.js.map +1 -1
- package/dist/esm/PivotViewer/components/DetailPanel.d.ts +3 -1
- package/dist/esm/PivotViewer/components/DetailPanel.d.ts.map +1 -1
- package/dist/esm/PivotViewer/components/DetailPanel.js +10 -3
- package/dist/esm/PivotViewer/components/DetailPanel.js.map +1 -1
- package/dist/esm/PivotViewer/components/PivotCanvas.d.ts +5 -2
- package/dist/esm/PivotViewer/components/PivotCanvas.d.ts.map +1 -1
- package/dist/esm/PivotViewer/components/PivotCanvas.js +30 -6
- package/dist/esm/PivotViewer/components/PivotCanvas.js.map +1 -1
- package/dist/esm/PivotViewer/components/PivotViewerMain.d.ts +5 -1
- package/dist/esm/PivotViewer/components/PivotViewerMain.d.ts.map +1 -1
- package/dist/esm/PivotViewer/components/PivotViewerMain.js +16 -5
- package/dist/esm/PivotViewer/components/PivotViewerMain.js.map +1 -1
- package/dist/esm/PivotViewer/components/Toolbar.d.ts +3 -1
- package/dist/esm/PivotViewer/components/Toolbar.d.ts.map +1 -1
- package/dist/esm/PivotViewer/components/Toolbar.js +34 -2
- package/dist/esm/PivotViewer/components/Toolbar.js.map +1 -1
- package/dist/esm/PivotViewer/components/pivot/constants.d.ts.map +1 -1
- package/dist/esm/PivotViewer/components/pivot/constants.js +5 -5
- package/dist/esm/PivotViewer/components/pivot/constants.js.map +1 -1
- package/dist/esm/PivotViewer/components/pivot/groups.d.ts.map +1 -1
- package/dist/esm/PivotViewer/components/pivot/groups.js +2 -2
- package/dist/esm/PivotViewer/components/pivot/groups.js.map +1 -1
- package/dist/esm/PivotViewer/components/pivot/sprites.d.ts +10 -2
- package/dist/esm/PivotViewer/components/pivot/sprites.d.ts.map +1 -1
- package/dist/esm/PivotViewer/components/pivot/sprites.js +10 -27
- package/dist/esm/PivotViewer/components/pivot/sprites.js.map +1 -1
- package/dist/esm/PivotViewer/components/pivot/visibility.d.ts.map +1 -1
- package/dist/esm/PivotViewer/components/pivot/visibility.js +8 -20
- package/dist/esm/PivotViewer/components/pivot/visibility.js.map +1 -1
- package/dist/esm/PivotViewer/constants.js +1 -2
- package/dist/esm/PivotViewer/constants.js.map +1 -1
- package/dist/esm/PivotViewer/engine/layout.js +1 -1
- package/dist/esm/PivotViewer/engine/layout.js.map +1 -1
- package/dist/esm/PivotViewer/hooks/useCardSelection.d.ts.map +1 -1
- package/dist/esm/PivotViewer/hooks/useCardSelection.js +2 -1
- package/dist/esm/PivotViewer/hooks/useCardSelection.js.map +1 -1
- package/dist/esm/PivotViewer/hooks/useZoomState.d.ts +1 -0
- package/dist/esm/PivotViewer/hooks/useZoomState.d.ts.map +1 -1
- package/dist/esm/PivotViewer/hooks/useZoomState.js +4 -0
- package/dist/esm/PivotViewer/hooks/useZoomState.js.map +1 -1
- package/dist/esm/PivotViewer/types.d.ts +5 -1
- package/dist/esm/PivotViewer/types.d.ts.map +1 -1
- package/dist/esm/PivotViewer/types.js.map +1 -1
- package/dist/esm/PivotViewer/utils/animations.js +1 -1
- package/dist/esm/PivotViewer/utils/animations.js.map +1 -1
- package/dist/esm/PivotViewer/utils/constants.d.ts +1 -1
- package/dist/esm/PivotViewer/utils/constants.d.ts.map +1 -1
- package/dist/esm/PivotViewer/utils/constants.js +1 -1
- package/dist/esm/PivotViewer/utils/constants.js.map +1 -1
- package/dist/esm/PivotViewer/utils/selection.d.ts.map +1 -1
- package/dist/esm/PivotViewer/utils/selection.js +8 -1
- package/dist/esm/PivotViewer/utils/selection.js.map +1 -1
- package/dist/esm/TimeMachine/TimeMachine.js +1 -1
- package/dist/esm/index.d.ts +5 -3
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +16 -12
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/package.json +3 -0
- package/dist/esm/tsconfig.tsbuildinfo +1 -1
- package/package.json +36 -78
|
@@ -23,7 +23,7 @@ function _interopNamespaceDefault(e) {
|
|
|
23
23
|
var PIXI__namespace = /*#__PURE__*/_interopNamespaceDefault(PIXI);
|
|
24
24
|
|
|
25
25
|
const spritePool = [];
|
|
26
|
-
function createCardSprite(id, x, y, items, onCardClick, onPanStart, cardWidth, cardHeight, cardColors) {
|
|
26
|
+
function createCardSprite(id, x, y, items, onCardClick, onPanStart, cardWidth, cardHeight, cardColors, cardRenderer, resolveId) {
|
|
27
27
|
if (spritePool.length > 0) {
|
|
28
28
|
const sprite = spritePool.pop();
|
|
29
29
|
if (sprite.container) {
|
|
@@ -92,7 +92,7 @@ function createCardSprite(id, x, y, items, onCardClick, onPanStart, cardWidth, c
|
|
|
92
92
|
}
|
|
93
93
|
}
|
|
94
94
|
if (sprite.container) {
|
|
95
|
-
sprite.container._eventContext = { items, onCardClick, id };
|
|
95
|
+
sprite.container._eventContext = { items, onCardClick, id, cardRenderer, resolveId };
|
|
96
96
|
}
|
|
97
97
|
return sprite;
|
|
98
98
|
}
|
|
@@ -101,7 +101,7 @@ function createCardSprite(id, x, y, items, onCardClick, onPanStart, cardWidth, c
|
|
|
101
101
|
container.cursor = 'pointer';
|
|
102
102
|
container.position.set(x, y);
|
|
103
103
|
container.hitArea = new PIXI__namespace.Rectangle(constants.CARD_GAP / 2, constants.CARD_GAP / 2, cardWidth - constants.CARD_GAP, cardHeight - constants.CARD_GAP);
|
|
104
|
-
container._eventContext = { items, onCardClick, id };
|
|
104
|
+
container._eventContext = { items, onCardClick, id, cardRenderer, resolveId };
|
|
105
105
|
const graphics = new PIXI__namespace.Graphics();
|
|
106
106
|
const actualWidth = cardWidth - constants.CARD_GAP;
|
|
107
107
|
const actualHeight = cardHeight - constants.CARD_GAP;
|
|
@@ -143,7 +143,8 @@ function createCardSprite(id, x, y, items, onCardClick, onPanStart, cardWidth, c
|
|
|
143
143
|
e.stopPropagation();
|
|
144
144
|
const ctx = container._eventContext;
|
|
145
145
|
const itemsArray = ctx.items;
|
|
146
|
-
const
|
|
146
|
+
const numericId = typeof ctx.id === 'number' ? ctx.id : Number(ctx.id);
|
|
147
|
+
const item = itemsArray[numericId];
|
|
147
148
|
if (item) {
|
|
148
149
|
ctx.onCardClick(item, e.nativeEvent, ctx.id);
|
|
149
150
|
}
|
|
@@ -173,32 +174,14 @@ function destroySprite(sprite) {
|
|
|
173
174
|
}
|
|
174
175
|
spritePool.push(sprite);
|
|
175
176
|
}
|
|
176
|
-
function updateCardContent(sprite, item, selectedId, cardWidth, cardHeight, cardColors) {
|
|
177
|
+
function updateCardContent(sprite, item, selectedId, cardWidth, cardHeight, cardColors, cardRenderer) {
|
|
177
178
|
if (!item)
|
|
178
179
|
return;
|
|
179
|
-
const event = item;
|
|
180
|
-
const eventType = String(event.type || event.name || event.title || 'Event');
|
|
181
|
-
const timeStr = event.occurred ? new Date(event.occurred).toLocaleString('en-US', {
|
|
182
|
-
month: '2-digit',
|
|
183
|
-
day: '2-digit',
|
|
184
|
-
year: 'numeric',
|
|
185
|
-
hour: '2-digit',
|
|
186
|
-
minute: '2-digit',
|
|
187
|
-
hour12: false
|
|
188
|
-
}).replace(',', '') : '';
|
|
189
|
-
const correlation = event.correlationId || event.correlation || '';
|
|
190
|
-
const correlationShort = correlation ? String(correlation).substring(0, 12) + '...' : '';
|
|
191
|
-
const maxTitleLength = 20;
|
|
192
|
-
const titleDisplay = eventType.length > maxTitleLength
|
|
193
|
-
? eventType.substring(0, maxTitleLength) + '...'
|
|
194
|
-
: eventType;
|
|
195
|
-
const maxTypeLength = 16;
|
|
196
|
-
const typeDisplay = eventType.length > maxTypeLength
|
|
197
|
-
? eventType.substring(0, maxTypeLength) + '...'
|
|
198
|
-
: eventType;
|
|
199
180
|
const colors = cardColors;
|
|
200
|
-
const
|
|
201
|
-
const
|
|
181
|
+
const cardData = cardRenderer(item);
|
|
182
|
+
const titleDisplay = cardData.title;
|
|
183
|
+
const labelsText = (cardData.labels || []).join('\n');
|
|
184
|
+
const valuesText = (cardData.values || []).join('\n');
|
|
202
185
|
const colorsChanged = sprite.lastCardColors !== colors;
|
|
203
186
|
if (!sprite.titleText || sprite.titleText.destroyed)
|
|
204
187
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sprites.js","sources":["../../../../../PivotViewer/components/pivot/sprites.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 { CARD_GAP, CARD_PADDING, CARD_RADIUS } from './constants';\nimport type { CardSprite, CardColors } from './constants';\n\nconst spritePool: CardSprite[] = [];\n\nexport function createCardSprite<TItem extends object>(\n id: number | string,\n x: number,\n y: number,\n items: TItem[],\n onCardClick: (item: TItem, e: MouseEvent, id: number | string) => void,\n onPanStart: (e: MouseEvent) => void,\n cardWidth: number,\n cardHeight: number,\n cardColors: CardColors,\n): CardSprite {\n if (spritePool.length > 0) {\n const sprite = spritePool.pop()!;\n if (sprite.container) {\n sprite.container.visible = true;\n sprite.container.alpha = 1;\n sprite.container.position.set(x, y);\n }\n sprite.itemId = id;\n sprite.targetX = x;\n sprite.targetY = y;\n sprite.currentX = x;\n sprite.currentY = y;\n\n // Reset animation state\n delete sprite.animationStartTime;\n delete sprite.animationDelay;\n delete sprite.startX;\n delete sprite.startY;\n\n // Reset cache\n sprite.lastSelectedId = null;\n sprite.lastCardColors = undefined;\n sprite.lastTitle = undefined;\n sprite.lastLabels = undefined;\n sprite.lastValues = undefined;\n\n // Recreate graphics if it was destroyed\n if (!sprite.graphics || sprite.graphics.destroyed) {\n sprite.graphics = new PIXI.Graphics();\n if (sprite.container) {\n sprite.container.addChildAt(sprite.graphics, 0);\n }\n }\n\n // Recreate text objects if they were destroyed\n const offsetX = CARD_GAP / 2;\n const offsetY = CARD_GAP / 2;\n \n if (!sprite.titleText || sprite.titleText.destroyed) {\n sprite.titleText = new PIXI.Text('', {\n fontSize: 13,\n fill: cardColors.text as string | number,\n fontWeight: '600',\n lineHeight: 18,\n wordWrap: false,\n } as PIXI.TextStyle);\n sprite.titleText.position.set(offsetX + CARD_PADDING, offsetY + CARD_PADDING);\n if (sprite.container) {\n sprite.container.addChild(sprite.titleText);\n }\n }\n\n if (!sprite.labelsText || sprite.labelsText.destroyed) {\n sprite.labelsText = new PIXI.Text('', {\n fontSize: 11,\n fill: cardColors.textSecondary as string | number,\n fontWeight: '400',\n lineHeight: 18,\n } as PIXI.TextStyle);\n sprite.labelsText.position.set(offsetX + CARD_PADDING, offsetY + CARD_PADDING + 40);\n if (sprite.container) {\n sprite.container.addChild(sprite.labelsText);\n }\n }\n\n if (!sprite.valuesText || sprite.valuesText.destroyed) {\n sprite.valuesText = new PIXI.Text('', {\n fontSize: 11,\n fill: cardColors.text as string | number,\n fontWeight: '500',\n lineHeight: 18,\n wordWrap: false,\n } as PIXI.TextStyle);\n sprite.valuesText.position.set(offsetX + CARD_PADDING + 65, offsetY + CARD_PADDING + 40);\n if (sprite.container) {\n sprite.container.addChild(sprite.valuesText);\n }\n }\n\n // Update event context\n if (sprite.container) {\n (sprite.container as unknown as { _eventContext: { items: TItem[]; onCardClick: (item: TItem, e: MouseEvent, id: number | string) => void; id: number | string } })._eventContext = { items, onCardClick, id };\n }\n\n return sprite;\n }\n\n const container = new PIXI.Container();\n container.eventMode = 'static';\n container.cursor = 'pointer';\n container.position.set(x, y);\n\n // Define hit area to match the visible card size (excluding gaps)\n // This ensures the entire card is clickable and avoids issues with text blocking hits\n container.hitArea = new PIXI.Rectangle(\n CARD_GAP / 2,\n CARD_GAP / 2,\n cardWidth - CARD_GAP,\n cardHeight - CARD_GAP\n );\n\n // Store context for event handlers\n (container as unknown as { _eventContext: { items: TItem[]; onCardClick: (item: TItem, e: MouseEvent, id: number | string) => void; id: number | string } })._eventContext = { items, onCardClick, id };\n\n const graphics = new PIXI.Graphics();\n\n const actualWidth = cardWidth - CARD_GAP;\n const actualHeight = cardHeight - CARD_GAP;\n const offsetX = CARD_GAP / 2;\n const offsetY = CARD_GAP / 2;\n\n const gradient = new PIXI.FillGradient(0, offsetY, 0, offsetY + actualHeight);\n gradient.addColorStop(0, cardColors.mid);\n gradient.addColorStop(1, cardColors.base);\n\n graphics.roundRect(offsetX, offsetY, actualWidth, actualHeight, CARD_RADIUS);\n graphics.fill(gradient);\n\n container.addChild(graphics);\n\n const titleText = new PIXI.Text('', {\n fontSize: 13,\n fill: cardColors.text as string | number,\n fontWeight: '600',\n lineHeight: 18,\n wordWrap: false,\n } as PIXI.TextStyle);\n titleText.position.set(offsetX + CARD_PADDING, offsetY + CARD_PADDING);\n container.addChild(titleText);\n\n const labelsText = new PIXI.Text('', {\n fontSize: 11,\n fill: cardColors.textSecondary as string | number,\n fontWeight: '400',\n lineHeight: 18,\n } as PIXI.TextStyle);\n labelsText.position.set(offsetX + CARD_PADDING, offsetY + CARD_PADDING + 40);\n container.addChild(labelsText);\n\n const valuesText = new PIXI.Text('', {\n fontSize: 11,\n fill: cardColors.text as string | number,\n fontWeight: '500',\n lineHeight: 18,\n wordWrap: false,\n } as PIXI.TextStyle);\n valuesText.position.set(offsetX + CARD_PADDING + 65, offsetY + CARD_PADDING + 40);\n container.addChild(valuesText);\n\n container.on('click', (e: PIXI.FederatedPointerEvent) => {\n e.stopPropagation();\n const ctx = (container as unknown as { _eventContext: { items: TItem[]; onCardClick: (item: TItem, e: MouseEvent, id: number | string) => void; id: number | string } })._eventContext;\n const itemsArray = ctx.items;\n const item = itemsArray[Number(ctx.id)];\n if (item) {\n ctx.onCardClick(item, e.nativeEvent as MouseEvent, ctx.id);\n }\n });\n\n container.on('pointerdown', (e: PIXI.FederatedPointerEvent) => {\n e.stopPropagation();\n // onPanStart(e.nativeEvent as MouseEvent);\n });\n\n return {\n container,\n graphics,\n titleText,\n labelsText,\n valuesText,\n itemId: id,\n targetX: x,\n targetY: y,\n currentX: x,\n currentY: y,\n };\n}\n\nexport function destroySprite(sprite: CardSprite) {\n if (sprite.container && sprite.container.parent) {\n sprite.container.parent.removeChild(sprite.container);\n }\n // Reset visibility to ensure it doesn't ghost if something goes wrong\n if (sprite.container) {\n sprite.container.visible = false;\n }\n spritePool.push(sprite);\n}\n\nexport function clearSpritePool() {\n for (const sprite of spritePool) {\n try {\n sprite.graphics?.destroy();\n sprite.titleText?.destroy();\n sprite.labelsText?.destroy();\n sprite.valuesText?.destroy();\n sprite.container?.destroy();\n } catch (e) {\n void e;\n }\n }\n spritePool.length = 0;\n}\n\n// Updated: Text objects now recreated when recycling pooled sprites\nexport function updateCardContent<TItem extends object>(\n sprite: CardSprite,\n item: TItem,\n selectedId: string | number | null,\n cardWidth: number,\n cardHeight: number,\n cardColors: CardColors,\n) {\n if (!item) return;\n\n const event = item as unknown as Record<string, unknown>;\n const eventType = String(event.type || event.name || event.title || 'Event');\n\n const timeStr = event.occurred ? new Date(event.occurred as string | number | Date).toLocaleString('en-US', {\n month: '2-digit',\n day: '2-digit',\n year: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n hour12: false\n }).replace(',', '') : '';\n\n const correlation = event.correlationId || event.correlation || '';\n const correlationShort = correlation ? String(correlation).substring(0, 12) + '...' : '';\n\n const maxTitleLength = 20;\n const titleDisplay = eventType.length > maxTitleLength\n ? eventType.substring(0, maxTitleLength) + '...'\n : eventType;\n\n const maxTypeLength = 16;\n const typeDisplay = eventType.length > maxTypeLength\n ? eventType.substring(0, maxTypeLength) + '...'\n : eventType;\n\n const colors = cardColors;\n const labelsText = 'Type\\nOccurred\\nCorrelation';\n const valuesText = `${typeDisplay}\\n${timeStr}\\n${correlationShort}`;\n const colorsChanged = sprite.lastCardColors !== colors;\n\n // Ensure text objects exist before using them\n if (!sprite.titleText || sprite.titleText.destroyed) return;\n if (!sprite.labelsText || sprite.labelsText.destroyed) return;\n if (!sprite.valuesText || sprite.valuesText.destroyed) return;\n\n if (sprite.lastTitle !== titleDisplay) {\n sprite.titleText.text = titleDisplay;\n sprite.lastTitle = titleDisplay;\n }\n\n if (sprite.lastLabels !== labelsText) {\n sprite.labelsText.text = labelsText;\n sprite.lastLabels = labelsText;\n }\n\n if (colorsChanged && sprite.labelsText.style) {\n (sprite.labelsText.style as unknown as { fill: string | number }).fill = colors.textSecondary;\n }\n\n if (sprite.lastValues !== valuesText) {\n sprite.valuesText.text = valuesText;\n sprite.lastValues = valuesText;\n }\n\n if (colorsChanged && sprite.valuesText.style) {\n (sprite.valuesText.style as unknown as { fill: string | number }).fill = colors.text;\n }\n\n sprite.titleText.visible = true;\n sprite.labelsText.visible = true;\n sprite.valuesText.visible = true;\n\n const isSelected = sprite.itemId === selectedId;\n\n // Only redraw graphics if selection state or colors changed\n if (sprite.lastSelectedId === selectedId && !colorsChanged && sprite.graphics) {\n return;\n }\n\n sprite.lastSelectedId = selectedId;\n sprite.lastCardColors = cardColors;\n\n // Ensure graphics exists before attempting to use it\n if (!sprite.graphics || sprite.graphics.destroyed) {\n sprite.graphics = new PIXI.Graphics();\n if (sprite.container) {\n sprite.container.addChildAt(sprite.graphics, 0);\n }\n } else {\n sprite.graphics.clear();\n }\n\n const actualWidth = cardWidth - CARD_GAP;\n const actualHeight = cardHeight - CARD_GAP;\n const offsetX = CARD_GAP / 2;\n const offsetY = CARD_GAP / 2;\n\n const gradient = new PIXI.FillGradient(0, offsetY, 0, offsetY + actualHeight);\n if (isSelected) {\n gradient.addColorStop(0, colors.gradient);\n gradient.addColorStop(1, colors.mid);\n } else {\n gradient.addColorStop(0, colors.mid);\n gradient.addColorStop(1, colors.base);\n }\n\n sprite.graphics.roundRect(offsetX, offsetY, actualWidth, actualHeight, CARD_RADIUS);\n \n // Ensure graphics is still valid before filling\n if (sprite.graphics && !sprite.graphics.destroyed) {\n sprite.graphics.fill(gradient);\n }\n\n if (isSelected) {\n if (sprite.graphics && !sprite.graphics.destroyed) {\n sprite.graphics.stroke({ width: 2, color: colors.border });\n }\n } else {\n if (sprite.graphics && !sprite.graphics.destroyed) {\n sprite.graphics.stroke({ width: 1, color: colors.border, alpha: 0.35 });\n }\n }\n}\n"],"names":["PIXI","CARD_GAP","CARD_PADDING","CARD_RADIUS"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sprites.js","sources":["../../../../../PivotViewer/components/pivot/sprites.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 { CARD_GAP, CARD_PADDING, CARD_RADIUS } from './constants';\nimport type { CardSprite, CardColors } from './constants';\n\nconst spritePool: CardSprite[] = [];\n\nexport function createCardSprite<TItem extends object>(\n id: number | string,\n x: number,\n y: number,\n items: TItem[],\n onCardClick: (item: TItem, e: MouseEvent, id: number | string) => void,\n onPanStart: (e: MouseEvent) => void,\n cardWidth: number,\n cardHeight: number,\n cardColors: CardColors,\n cardRenderer: (item: TItem) => { title: string; labels?: string[]; values?: string[] },\n resolveId: (item: TItem, index: number) => string | number,\n): CardSprite {\n if (spritePool.length > 0) {\n const sprite = spritePool.pop()!;\n if (sprite.container) {\n sprite.container.visible = true;\n sprite.container.alpha = 1;\n sprite.container.position.set(x, y);\n }\n sprite.itemId = id;\n sprite.targetX = x;\n sprite.targetY = y;\n sprite.currentX = x;\n sprite.currentY = y;\n\n // Reset animation state\n delete sprite.animationStartTime;\n delete sprite.animationDelay;\n delete sprite.startX;\n delete sprite.startY;\n\n // Reset cache\n sprite.lastSelectedId = null;\n sprite.lastCardColors = undefined;\n sprite.lastTitle = undefined;\n sprite.lastLabels = undefined;\n sprite.lastValues = undefined;\n\n // Recreate graphics if it was destroyed\n if (!sprite.graphics || sprite.graphics.destroyed) {\n sprite.graphics = new PIXI.Graphics();\n if (sprite.container) {\n sprite.container.addChildAt(sprite.graphics, 0);\n }\n }\n\n // Recreate text objects if they were destroyed\n const offsetX = CARD_GAP / 2;\n const offsetY = CARD_GAP / 2;\n \n if (!sprite.titleText || sprite.titleText.destroyed) {\n sprite.titleText = new PIXI.Text('', {\n fontSize: 13,\n fill: cardColors.text as string | number,\n fontWeight: '600',\n lineHeight: 18,\n wordWrap: false,\n } as PIXI.TextStyle);\n sprite.titleText.position.set(offsetX + CARD_PADDING, offsetY + CARD_PADDING);\n if (sprite.container) {\n sprite.container.addChild(sprite.titleText);\n }\n }\n\n if (!sprite.labelsText || sprite.labelsText.destroyed) {\n sprite.labelsText = new PIXI.Text('', {\n fontSize: 11,\n fill: cardColors.textSecondary as string | number,\n fontWeight: '400',\n lineHeight: 18,\n } as PIXI.TextStyle);\n sprite.labelsText.position.set(offsetX + CARD_PADDING, offsetY + CARD_PADDING + 40);\n if (sprite.container) {\n sprite.container.addChild(sprite.labelsText);\n }\n }\n\n if (!sprite.valuesText || sprite.valuesText.destroyed) {\n sprite.valuesText = new PIXI.Text('', {\n fontSize: 11,\n fill: cardColors.text as string | number,\n fontWeight: '500',\n lineHeight: 18,\n wordWrap: false,\n } as PIXI.TextStyle);\n sprite.valuesText.position.set(offsetX + CARD_PADDING + 65, offsetY + CARD_PADDING + 40);\n if (sprite.container) {\n sprite.container.addChild(sprite.valuesText);\n }\n }\n\n // Update event context\n if (sprite.container) {\n (sprite.container as unknown as { _eventContext: { items: TItem[]; onCardClick: (item: TItem, e: MouseEvent, id: number | string) => void; id: number | string; cardRenderer: (item: TItem) => { title: string; labels?: string[]; values?: string[] }; resolveId: (item: TItem, index: number) => string | number } })._eventContext = { items, onCardClick, id, cardRenderer, resolveId };\n }\n\n return sprite;\n }\n\n const container = new PIXI.Container();\n container.eventMode = 'static';\n container.cursor = 'pointer';\n container.position.set(x, y);\n\n // Define hit area to match the visible card size (excluding gaps)\n // This ensures the entire card is clickable and avoids issues with text blocking hits\n container.hitArea = new PIXI.Rectangle(\n CARD_GAP / 2,\n CARD_GAP / 2,\n cardWidth - CARD_GAP,\n cardHeight - CARD_GAP\n );\n\n // Container configured for pointer interactions; hitArea matches visible card.\n\n // Store context for event handlers\n (container as unknown as { _eventContext: { items: TItem[]; onCardClick: (item: TItem, e: MouseEvent, id: number | string) => void; id: number | string; cardRenderer: (item: TItem) => { title: string; labels?: string[]; values?: string[] }; resolveId: (item: TItem, index: number) => string | number } })._eventContext = { items, onCardClick, id, cardRenderer, resolveId };\n\n const graphics = new PIXI.Graphics();\n\n const actualWidth = cardWidth - CARD_GAP;\n const actualHeight = cardHeight - CARD_GAP;\n const offsetX = CARD_GAP / 2;\n const offsetY = CARD_GAP / 2;\n\n const gradient = new PIXI.FillGradient(0, offsetY, 0, offsetY + actualHeight);\n gradient.addColorStop(0, cardColors.mid);\n gradient.addColorStop(1, cardColors.base);\n\n graphics.roundRect(offsetX, offsetY, actualWidth, actualHeight, CARD_RADIUS);\n graphics.fill(gradient);\n\n container.addChild(graphics);\n\n const titleText = new PIXI.Text('', {\n fontSize: 13,\n fill: cardColors.text as string | number,\n fontWeight: '600',\n lineHeight: 18,\n wordWrap: false,\n } as PIXI.TextStyle);\n titleText.position.set(offsetX + CARD_PADDING, offsetY + CARD_PADDING);\n container.addChild(titleText);\n\n const labelsText = new PIXI.Text('', {\n fontSize: 11,\n fill: cardColors.textSecondary as string | number,\n fontWeight: '400',\n lineHeight: 18,\n } as PIXI.TextStyle);\n labelsText.position.set(offsetX + CARD_PADDING, offsetY + CARD_PADDING + 40);\n container.addChild(labelsText);\n\n const valuesText = new PIXI.Text('', {\n fontSize: 11,\n fill: cardColors.text as string | number,\n fontWeight: '500',\n lineHeight: 18,\n wordWrap: false,\n } as PIXI.TextStyle);\n valuesText.position.set(offsetX + CARD_PADDING + 65, offsetY + CARD_PADDING + 40);\n container.addChild(valuesText);\n\n container.on('click', (e: PIXI.FederatedPointerEvent) => {\n e.stopPropagation();\n const ctx = (container as unknown as { _eventContext: { items: TItem[]; onCardClick: (item: TItem, e: MouseEvent, id: number | string) => void; id: number | string } })._eventContext;\n const itemsArray = ctx.items;\n const numericId = typeof ctx.id === 'number' ? ctx.id : Number(ctx.id);\n const item = itemsArray[numericId];\n if (item) {\n ctx.onCardClick(item, e.nativeEvent as MouseEvent, ctx.id);\n }\n });\n\n container.on('pointerdown', (e: PIXI.FederatedPointerEvent) => {\n e.stopPropagation();\n // onPanStart(e.nativeEvent as MouseEvent);\n });\n\n return {\n container,\n graphics,\n titleText,\n labelsText,\n valuesText,\n itemId: id,\n targetX: x,\n targetY: y,\n currentX: x,\n currentY: y,\n };\n}\n\nexport function destroySprite(sprite: CardSprite) {\n if (sprite.container && sprite.container.parent) {\n sprite.container.parent.removeChild(sprite.container);\n }\n // Reset visibility to ensure it doesn't ghost if something goes wrong\n if (sprite.container) {\n sprite.container.visible = false;\n }\n spritePool.push(sprite);\n}\n\nexport function clearSpritePool() {\n for (const sprite of spritePool) {\n try {\n sprite.graphics?.destroy();\n sprite.titleText?.destroy();\n sprite.labelsText?.destroy();\n sprite.valuesText?.destroy();\n sprite.container?.destroy();\n } catch (e) {\n void e;\n }\n }\n spritePool.length = 0;\n}\n\n// Updated: Text objects now recreated when recycling pooled sprites\nexport function updateCardContent<TItem extends object>(\n sprite: CardSprite,\n item: TItem,\n selectedId: string | number | null,\n cardWidth: number,\n cardHeight: number,\n cardColors: CardColors,\n cardRenderer: (item: TItem) => { title: string; labels?: string[]; values?: string[] },\n) {\n if (!item) return;\n\n // Selection rendering depends on sprite.itemId matching selectedId\n\n const colors = cardColors;\n const cardData = cardRenderer(item);\n const titleDisplay = cardData.title;\n const labelsText = (cardData.labels || []).join('\\n');\n const valuesText = (cardData.values || []).join('\\n');\n const colorsChanged = sprite.lastCardColors !== colors;\n\n // Ensure text objects exist before using them\n if (!sprite.titleText || sprite.titleText.destroyed) return;\n if (!sprite.labelsText || sprite.labelsText.destroyed) return;\n if (!sprite.valuesText || sprite.valuesText.destroyed) return;\n\n if (sprite.lastTitle !== titleDisplay) {\n sprite.titleText.text = titleDisplay;\n sprite.lastTitle = titleDisplay;\n }\n\n if (sprite.lastLabels !== labelsText) {\n sprite.labelsText.text = labelsText;\n sprite.lastLabels = labelsText;\n }\n\n if (colorsChanged && sprite.labelsText.style) {\n (sprite.labelsText.style as unknown as { fill: string | number }).fill = colors.textSecondary;\n }\n\n if (sprite.lastValues !== valuesText) {\n sprite.valuesText.text = valuesText;\n sprite.lastValues = valuesText;\n }\n\n if (colorsChanged && sprite.valuesText.style) {\n (sprite.valuesText.style as unknown as { fill: string | number }).fill = colors.text;\n }\n\n sprite.titleText.visible = true;\n sprite.labelsText.visible = true;\n sprite.valuesText.visible = true;\n\n const isSelected = sprite.itemId === selectedId;\n\n // Only redraw graphics if selection state or colors changed\n if (sprite.lastSelectedId === selectedId && !colorsChanged && sprite.graphics) {\n return;\n }\n\n sprite.lastSelectedId = selectedId;\n sprite.lastCardColors = cardColors;\n\n // Ensure graphics exists before attempting to use it\n if (!sprite.graphics || sprite.graphics.destroyed) {\n sprite.graphics = new PIXI.Graphics();\n if (sprite.container) {\n sprite.container.addChildAt(sprite.graphics, 0);\n }\n } else {\n sprite.graphics.clear();\n }\n\n const actualWidth = cardWidth - CARD_GAP;\n const actualHeight = cardHeight - CARD_GAP;\n const offsetX = CARD_GAP / 2;\n const offsetY = CARD_GAP / 2;\n\n const gradient = new PIXI.FillGradient(0, offsetY, 0, offsetY + actualHeight);\n if (isSelected) {\n gradient.addColorStop(0, colors.gradient);\n gradient.addColorStop(1, colors.mid);\n } else {\n gradient.addColorStop(0, colors.mid);\n gradient.addColorStop(1, colors.base);\n }\n\n sprite.graphics.roundRect(offsetX, offsetY, actualWidth, actualHeight, CARD_RADIUS);\n \n // Ensure graphics is still valid before filling\n if (sprite.graphics && !sprite.graphics.destroyed) {\n sprite.graphics.fill(gradient);\n }\n\n if (isSelected) {\n if (sprite.graphics && !sprite.graphics.destroyed) {\n sprite.graphics.stroke({ width: 2, color: colors.border });\n }\n } else {\n if (sprite.graphics && !sprite.graphics.destroyed) {\n sprite.graphics.stroke({ width: 1, color: colors.border, alpha: 0.35 });\n }\n }\n}\n"],"names":["PIXI","CARD_GAP","CARD_PADDING","CARD_RADIUS"],"mappings":"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"}
|
|
@@ -24,21 +24,6 @@ function syncSpritesToViewport(params) {
|
|
|
24
24
|
groupsContainer.scale.set(zoomLevel);
|
|
25
25
|
groupsContainer.position.set(-actualScrollX, offsetY - actualScrollY);
|
|
26
26
|
}
|
|
27
|
-
if (isViewTransition && (panDeltaX || panDeltaY)) {
|
|
28
|
-
const dx = (panDeltaX || 0) / (zoomLevel || 1);
|
|
29
|
-
const dy = (panDeltaY || 0) / (zoomLevel || 1);
|
|
30
|
-
for (const sprite of sprites$1.values()) {
|
|
31
|
-
if (sprite.animationStartTime !== undefined) {
|
|
32
|
-
if (sprite.startX !== undefined)
|
|
33
|
-
sprite.startX += dx;
|
|
34
|
-
if (sprite.startY !== undefined)
|
|
35
|
-
sprite.startY += dy;
|
|
36
|
-
sprite.currentX += dx;
|
|
37
|
-
sprite.currentY += dy;
|
|
38
|
-
sprite.container?.position?.set(sprite.currentX, sprite.currentY);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
27
|
const visibleSet = new Set();
|
|
43
28
|
const baseBufferWorld = Math.max(cardWidth, cardHeight) * 4;
|
|
44
29
|
const invScale = zoomLevel && zoomLevel !== 0 ? 1 / zoomLevel : 1;
|
|
@@ -245,14 +230,17 @@ function syncSpritesToViewport(params) {
|
|
|
245
230
|
sprite.animationDelay = Math.random() * 300;
|
|
246
231
|
}
|
|
247
232
|
}
|
|
248
|
-
|
|
233
|
+
const targetChanged = sprite.targetX !== position.x || sprite.targetY !== position.y;
|
|
234
|
+
if (targetChanged) {
|
|
249
235
|
if (isViewTransition) {
|
|
250
|
-
sprite.
|
|
251
|
-
|
|
236
|
+
if (sprite.animationStartTime === undefined) {
|
|
237
|
+
sprite.startX = sprite.currentX;
|
|
238
|
+
sprite.startY = sprite.currentY;
|
|
239
|
+
sprite.animationStartTime = Date.now();
|
|
240
|
+
sprite.animationDelay = Math.random() * 300;
|
|
241
|
+
}
|
|
252
242
|
sprite.targetX = position.x;
|
|
253
243
|
sprite.targetY = position.y;
|
|
254
|
-
sprite.animationStartTime = Date.now();
|
|
255
|
-
sprite.animationDelay = Math.random() * 300;
|
|
256
244
|
}
|
|
257
245
|
else {
|
|
258
246
|
sprite.targetX = position.x;
|
|
@@ -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 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, prevScrollTop, prevScrollLeft } = 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 // Apply pan delta to animating sprites to keep them visually stable during camera jumps\n if (isViewTransition && (panDeltaX || panDeltaY)) {\n const dx = (panDeltaX || 0) / (zoomLevel || 1);\n const dy = (panDeltaY || 0) / (zoomLevel || 1);\n\n for (const sprite of sprites.values()) {\n if (sprite.animationStartTime !== undefined) {\n if (sprite.startX !== undefined) sprite.startX += dx;\n if (sprite.startY !== undefined) sprite.startY += dy;\n sprite.currentX += dx;\n sprite.currentY += dy;\n sprite.container?.position?.set(sprite.currentX, sprite.currentY);\n }\n }\n }\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 // Scale epsilon with invScale so tolerance grows when zoomed out.\n const worldEpsilon = Math.max(0.5, 0.5 * invScale);\n\n // Iterate layout positions directly to avoid depending on `visibleIds`\n // which may be calculated in a different coordinate space or with\n // different assumptions about zoom. Looping the positions map is\n // deterministic and uses world coordinates directly.\n for (const [id, position] of layout.positions) {\n if (!position) continue;\n const worldX = position.x;\n const worldY = position.y;\n const worldCardW = cardWidth;\n const worldCardH = cardHeight;\n\n if (\n worldX + worldCardW >= viewportLeftWorld - worldEpsilon &&\n worldX <= viewportRightWorld + worldEpsilon &&\n worldY + worldCardH >= viewportTopWorld - worldEpsilon &&\n worldY <= viewportBottomWorld + worldEpsilon\n ) {\n inViewportIds.push(id);\n visibleSet.add(id);\n }\n }\n\n // During view transitions, if no cards are visible and we're not animating yet,\n // force-add the first few cards from the layout to ensure content appears.\n // This prevents a blank screen when switching modes, especially in packaged builds\n // where scroll stabilization might be delayed.\n if (isViewTransition && inViewportIds.length === 0 && layout.positions.size > 0) {\n let count = 0;\n for (const [id, position] of layout.positions) {\n if (count < 5 && position) { // Add up to 5 cards\n inViewportIds.push(id);\n visibleSet.add(id);\n count++;\n }\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 // Fallback: if no sprites are calculated as visible (e.g., due to rounding\n // or scroll/zoom race conditions), force a handful of cards into view so\n // the canvas never renders empty at certain zoom levels.\n // When transitioning views, be more aggressive to ensure content appears during the transition\n let injectedFallback = false;\n const fallbackCount = isViewTransition ? 30 : 12;\n if (inViewportIds.length === 0 && layout.positions.size > 0) {\n injectedFallback = true;\n let count = 0;\n for (const [id] of layout.positions) {\n inViewportIds.push(id);\n visibleSet.add(id);\n count++;\n if (count >= fallbackCount) break;\n }\n }\n\n // If we detect a very large discrepancy between created sprites and the\n // computed in-viewport count, that's a signal our culling math may be\n // unstable (especially at non-100% zoom). In that case, skip hiding this\n // frame as a conservative safeguard to avoid mass disappearing tiles.\n // However, disable this safeguard during view transitions to ensure old sprites are cleaned up.\n // EXCEPT: During view transitions, if scroll position hasn't stabilized yet (e.g., switching to grouped\n // mode triggers a scroll-to-bottom), keep all sprites visible to prevent flickering.\n // Check scroll stabilization by comparing current scroll to previous scroll position.\n const currentScrollTop = container.scrollTop || 0;\n const currentScrollLeft = container.scrollLeft || 0;\n const scrollTopDelta = Math.abs(currentScrollTop - (prevScrollTop || currentScrollTop));\n const scrollLeftDelta = Math.abs(currentScrollLeft - (prevScrollLeft || currentScrollLeft));\n const scrollStabilized = scrollTopDelta < 10 && scrollLeftDelta < 10;\n const aggressiveCull = !injectedFallback && (\n (!isViewTransition && sprites.size > Math.max(120, Math.ceil(inViewportIds.length * 1.5))) ||\n (isViewTransition && !scrollStabilized)\n );\n\n for (const [id, sprite] of sprites) {\n if (!visibleSet.has(id)) {\n // If view transition is active, check if this sprite has a valid target in the new layout\n // If so, keep it visible and animate it to the new position (even if off-screen)\n if (isViewTransition && layout.positions.has(id)) {\n const newPos = layout.positions.get(id);\n if (newPos) {\n sprite.targetX = newPos.x;\n sprite.targetY = newPos.y;\n\n // Trigger animation if not already animating\n if (sprite.animationStartTime === undefined) {\n sprite.startX = sprite.currentX;\n sprite.startY = sprite.currentY;\n sprite.animationStartTime = Date.now();\n sprite.animationDelay = Math.random() * 300;\n }\n\n try { if (sprite.container) sprite.container.visible = true; } catch (e) { void e; }\n // Don't mark as hidden, so it won't be swept\n if ((sprite as unknown as { __lastHiddenAt?: number }).__lastHiddenAt) delete (sprite as unknown as { __lastHiddenAt?: number }).__lastHiddenAt;\n continue;\n }\n }\n\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 && 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) {\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 (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 if (sprite.targetX !== position.x || sprite.targetY !== position.y) {\n if (isViewTransition) {\n sprite.startX = sprite.currentX;\n sprite.startY = sprite.currentY;\n sprite.targetX = position.x;\n sprite.targetY = position.y;\n sprite.animationStartTime = Date.now();\n // Add random delay for \"organic\" fly effect\n sprite.animationDelay = Math.random() * 300;\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":["sprites","CARD_GAP","destroySprite"],"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 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, prevScrollTop, prevScrollLeft } = 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 // Scale epsilon with invScale so tolerance grows when zoomed out.\n const worldEpsilon = Math.max(0.5, 0.5 * invScale);\n\n // Iterate layout positions directly to avoid depending on `visibleIds`\n // which may be calculated in a different coordinate space or with\n // different assumptions about zoom. Looping the positions map is\n // deterministic and uses world coordinates directly.\n for (const [id, position] of layout.positions) {\n if (!position) continue;\n const worldX = position.x;\n const worldY = position.y;\n const worldCardW = cardWidth;\n const worldCardH = cardHeight;\n\n if (\n worldX + worldCardW >= viewportLeftWorld - worldEpsilon &&\n worldX <= viewportRightWorld + worldEpsilon &&\n worldY + worldCardH >= viewportTopWorld - worldEpsilon &&\n worldY <= viewportBottomWorld + worldEpsilon\n ) {\n inViewportIds.push(id);\n visibleSet.add(id);\n }\n }\n\n // During view transitions, if no cards are visible and we're not animating yet,\n // force-add the first few cards from the layout to ensure content appears.\n // This prevents a blank screen when switching modes, especially in packaged builds\n // where scroll stabilization might be delayed.\n if (isViewTransition && inViewportIds.length === 0 && layout.positions.size > 0) {\n let count = 0;\n for (const [id, position] of layout.positions) {\n if (count < 5 && position) { // Add up to 5 cards\n inViewportIds.push(id);\n visibleSet.add(id);\n count++;\n }\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 // Fallback: if no sprites are calculated as visible (e.g., due to rounding\n // or scroll/zoom race conditions), force a handful of cards into view so\n // the canvas never renders empty at certain zoom levels.\n // When transitioning views, be more aggressive to ensure content appears during the transition\n let injectedFallback = false;\n const fallbackCount = isViewTransition ? 30 : 12;\n if (inViewportIds.length === 0 && layout.positions.size > 0) {\n injectedFallback = true;\n let count = 0;\n for (const [id] of layout.positions) {\n inViewportIds.push(id);\n visibleSet.add(id);\n count++;\n if (count >= fallbackCount) break;\n }\n }\n\n // If we detect a very large discrepancy between created sprites and the\n // computed in-viewport count, that's a signal our culling math may be\n // unstable (especially at non-100% zoom). In that case, skip hiding this\n // frame as a conservative safeguard to avoid mass disappearing tiles.\n // However, disable this safeguard during view transitions to ensure old sprites are cleaned up.\n // EXCEPT: During view transitions, if scroll position hasn't stabilized yet (e.g., switching to grouped\n // mode triggers a scroll-to-bottom), keep all sprites visible to prevent flickering.\n // Check scroll stabilization by comparing current scroll to previous scroll position.\n const currentScrollTop = container.scrollTop || 0;\n const currentScrollLeft = container.scrollLeft || 0;\n const scrollTopDelta = Math.abs(currentScrollTop - (prevScrollTop || currentScrollTop));\n const scrollLeftDelta = Math.abs(currentScrollLeft - (prevScrollLeft || currentScrollLeft));\n const scrollStabilized = scrollTopDelta < 10 && scrollLeftDelta < 10;\n const aggressiveCull = !injectedFallback && (\n (!isViewTransition && sprites.size > Math.max(120, Math.ceil(inViewportIds.length * 1.5))) ||\n (isViewTransition && !scrollStabilized)\n );\n\n for (const [id, sprite] of sprites) {\n if (!visibleSet.has(id)) {\n // If view transition is active, check if this sprite has a valid target in the new layout\n // If so, keep it visible and animate it to the new position (even if off-screen)\n if (isViewTransition && layout.positions.has(id)) {\n const newPos = layout.positions.get(id);\n if (newPos) {\n sprite.targetX = newPos.x;\n sprite.targetY = newPos.y;\n\n // Trigger animation if not already animating\n if (sprite.animationStartTime === undefined) {\n sprite.startX = sprite.currentX;\n sprite.startY = sprite.currentY;\n sprite.animationStartTime = Date.now();\n sprite.animationDelay = Math.random() * 300;\n }\n\n try { if (sprite.container) sprite.container.visible = true; } catch (e) { void e; }\n // Don't mark as hidden, so it won't be swept\n if ((sprite as unknown as { __lastHiddenAt?: number }).__lastHiddenAt) delete (sprite as unknown as { __lastHiddenAt?: number }).__lastHiddenAt;\n continue;\n }\n }\n\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 && 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) {\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 (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":["sprites","CARD_GAP","destroySprite"],"mappings":"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"}
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
const BASE_CARD_WIDTH = 200;
|
|
4
4
|
const BASE_CARD_HEIGHT = 176;
|
|
5
5
|
const CARDS_PER_COLUMN = 5;
|
|
6
|
-
const GROUP_SPACING = 20;
|
|
7
6
|
const CARD_GAP = 10;
|
|
8
7
|
const CANVAS_PADDING = 20;
|
|
9
8
|
|
|
@@ -12,5 +11,4 @@ exports.BASE_CARD_WIDTH = BASE_CARD_WIDTH;
|
|
|
12
11
|
exports.CANVAS_PADDING = CANVAS_PADDING;
|
|
13
12
|
exports.CARDS_PER_COLUMN = CARDS_PER_COLUMN;
|
|
14
13
|
exports.CARD_GAP = CARD_GAP;
|
|
15
|
-
exports.GROUP_SPACING = GROUP_SPACING;
|
|
16
14
|
//# sourceMappingURL=constants.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sources":["../../../PivotViewer/constants.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\nexport const BASE_CARD_WIDTH = 200;\nexport const BASE_CARD_HEIGHT = 176;\nexport const CARDS_PER_COLUMN = 5;\nexport const GROUP_SPACING = 20;\nexport const CARD_GAP = 10;\nexport const CANVAS_PADDING = 20;\n"],"names":[],"mappings":";;AAGO,MAAM,eAAe,GAAG;AACxB,MAAM,gBAAgB,GAAG;AACzB,MAAM,gBAAgB,GAAG;
|
|
1
|
+
{"version":3,"file":"constants.js","sources":["../../../PivotViewer/constants.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\nexport const BASE_CARD_WIDTH = 200;\nexport const BASE_CARD_HEIGHT = 176;\nexport const CARDS_PER_COLUMN = 5;\nexport const GROUP_SPACING = 20;\nexport const CARD_GAP = 10;\nexport const CANVAS_PADDING = 20;\n"],"names":[],"mappings":";;AAGO,MAAM,eAAe,GAAG;AACxB,MAAM,gBAAgB,GAAG;AACzB,MAAM,gBAAgB,GAAG;AAEzB,MAAM,QAAQ,GAAG;AACjB,MAAM,cAAc,GAAG;;;;;;;;"}
|
|
@@ -51,7 +51,7 @@ function computeGroupedLayout(grouping, spec, positions) {
|
|
|
51
51
|
const effectiveGroupSpacing = 0;
|
|
52
52
|
const slotWidth = cardWidth + constants.CARD_GAP;
|
|
53
53
|
const slotHeight = cardHeight + constants.CARD_GAP;
|
|
54
|
-
const BOTTOM_MARGIN =
|
|
54
|
+
const BOTTOM_MARGIN = constants.CANVAS_PADDING;
|
|
55
55
|
const COLUMNS_PER_BUCKET = 2;
|
|
56
56
|
const bucketWidth = COLUMNS_PER_BUCKET * slotWidth;
|
|
57
57
|
let groupX = 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.js","sources":["../../../../PivotViewer/engine/layout.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 {\n LayoutSpec,\n LayoutResult,\n ItemPosition,\n GroupingResult,\n ItemId,\n} from './types';\nimport { CARD_GAP, CANVAS_PADDING } from '../constants';\n\nexport function computeLayout(\n grouping: GroupingResult,\n spec: LayoutSpec\n): LayoutResult {\n const positions = new Map<ItemId, ItemPosition>();\n\n if (spec.viewMode === 'collection') {\n return computeCollectionLayout(grouping, spec, positions);\n } else {\n return computeGroupedLayout(grouping, spec, positions);\n }\n}\n\nfunction computeCollectionLayout(\n grouping: GroupingResult,\n spec: LayoutSpec,\n positions: Map<ItemId, ItemPosition>\n): LayoutResult {\n const { cardWidth, cardHeight, containerWidth } = spec;\n const slotWidth = cardWidth + CARD_GAP;\n const slotHeight = cardHeight + CARD_GAP;\n\n // Calculate how many cards fit per row based on container width (include gap)\n const cardsPerRow = Math.max(1, Math.floor((containerWidth + CARD_GAP - (CANVAS_PADDING * 2)) / slotWidth));\n\n let x = CANVAS_PADDING;\n let y = CANVAS_PADDING;\n let column = 0;\n let itemCount = 0;\n\n for (const group of grouping.groups) {\n for (let i = 0; i < group.ids.length; i++) {\n const id = group.ids[i];\n\n positions.set(id, {\n x,\n y,\n groupIndex: 0,\n });\n\n // Move to next position horizontally (left to right)\n column++;\n x += slotWidth;\n\n // Wrap to next row when we've filled the width\n if (column >= cardsPerRow) {\n column = 0;\n x = CANVAS_PADDING;\n y += slotHeight;\n }\n\n itemCount++;\n }\n }\n\n const rows = Math.ceil(itemCount / cardsPerRow);\n const contentWidth = Math.min(itemCount, cardsPerRow) * slotWidth;\n\n return {\n positions,\n totalWidth: Math.max(containerWidth, contentWidth + (CANVAS_PADDING * 2)),\n totalHeight: (rows * slotHeight) + (CANVAS_PADDING * 2),\n };\n}\n\nfunction computeGroupedLayout(\n grouping: GroupingResult,\n spec: LayoutSpec,\n positions: Map<ItemId, ItemPosition>\n): LayoutResult {\n const { cardWidth, cardHeight, cardsPerColumn } = spec;\n // Override group spacing to ensure consistent card spacing across groups\n // We want visual gap between groups to match gap between cards (CARD_GAP)\n const effectiveGroupSpacing = 0;\n\n const slotWidth = cardWidth + CARD_GAP;\n const slotHeight = cardHeight + CARD_GAP;\n // Bottom margin
|
|
1
|
+
{"version":3,"file":"layout.js","sources":["../../../../PivotViewer/engine/layout.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 {\n LayoutSpec,\n LayoutResult,\n ItemPosition,\n GroupingResult,\n ItemId,\n} from './types';\nimport { CARD_GAP, CANVAS_PADDING } from '../constants';\n\nexport function computeLayout(\n grouping: GroupingResult,\n spec: LayoutSpec\n): LayoutResult {\n const positions = new Map<ItemId, ItemPosition>();\n\n if (spec.viewMode === 'collection') {\n return computeCollectionLayout(grouping, spec, positions);\n } else {\n return computeGroupedLayout(grouping, spec, positions);\n }\n}\n\nfunction computeCollectionLayout(\n grouping: GroupingResult,\n spec: LayoutSpec,\n positions: Map<ItemId, ItemPosition>\n): LayoutResult {\n const { cardWidth, cardHeight, containerWidth } = spec;\n const slotWidth = cardWidth + CARD_GAP;\n const slotHeight = cardHeight + CARD_GAP;\n\n // Calculate how many cards fit per row based on container width (include gap)\n const cardsPerRow = Math.max(1, Math.floor((containerWidth + CARD_GAP - (CANVAS_PADDING * 2)) / slotWidth));\n\n let x = CANVAS_PADDING;\n let y = CANVAS_PADDING;\n let column = 0;\n let itemCount = 0;\n\n for (const group of grouping.groups) {\n for (let i = 0; i < group.ids.length; i++) {\n const id = group.ids[i];\n\n positions.set(id, {\n x,\n y,\n groupIndex: 0,\n });\n\n // Move to next position horizontally (left to right)\n column++;\n x += slotWidth;\n\n // Wrap to next row when we've filled the width\n if (column >= cardsPerRow) {\n column = 0;\n x = CANVAS_PADDING;\n y += slotHeight;\n }\n\n itemCount++;\n }\n }\n\n const rows = Math.ceil(itemCount / cardsPerRow);\n const contentWidth = Math.min(itemCount, cardsPerRow) * slotWidth;\n\n return {\n positions,\n totalWidth: Math.max(containerWidth, contentWidth + (CANVAS_PADDING * 2)),\n totalHeight: (rows * slotHeight) + (CANVAS_PADDING * 2),\n };\n}\n\nfunction computeGroupedLayout(\n grouping: GroupingResult,\n spec: LayoutSpec,\n positions: Map<ItemId, ItemPosition>\n): LayoutResult {\n const { cardWidth, cardHeight, cardsPerColumn } = spec;\n // Override group spacing to ensure consistent card spacing across groups\n // We want visual gap between groups to match gap between cards (CARD_GAP)\n const effectiveGroupSpacing = 0;\n\n const slotWidth = cardWidth + CARD_GAP;\n const slotHeight = cardHeight + CARD_GAP;\n // Bottom margin matches the canvas padding for visual consistency\n const BOTTOM_MARGIN = CANVAS_PADDING;\n\n // Fixed bucket width: 2 columns of cards per bucket (always)\n const COLUMNS_PER_BUCKET = 2;\n const bucketWidth = COLUMNS_PER_BUCKET * slotWidth;\n\n let groupX = 0;\n // Use container height for layout, or fallback to cardsPerColumn height\n const layoutHeight = spec.containerHeight || (cardsPerColumn * slotHeight);\n const bucketWidths: number[] = [];\n const groupXs: number[] = [];\n let maxRows = 0;\n\n // First pass: calculate max rows to determine total height\n for (const group of grouping.groups) {\n const itemsInGroup = group.ids.length;\n const rowsInGroup = Math.ceil(itemsInGroup / COLUMNS_PER_BUCKET);\n maxRows = Math.max(maxRows, rowsInGroup);\n }\n\n // Calculate actual content height needed (ensure it's at least as tall as the container)\n // We need to fit the tallest column plus the bottom margin\n const contentHeight = Math.max(layoutHeight, (maxRows * slotHeight) + BOTTOM_MARGIN);\n\n for (let groupIndex = 0; groupIndex < grouping.groups.length; groupIndex++) {\n const group = grouping.groups[groupIndex];\n groupXs.push(groupX);\n\n const itemsInGroup = group.ids.length;\n\n for (let i = 0; i < itemsInGroup; i++) {\n const id = group.ids[i];\n\n // Cards fill from left to right, bottom to top\n // For a 2-column bucket: i=0,1 in row 0; i=2,3 in row 1; etc.\n const col = i % COLUMNS_PER_BUCKET;\n const row = Math.floor(i / COLUMNS_PER_BUCKET);\n\n // Center the cards within the bucket\n // The bucket width fits 2 slots (2W + 2G). Cards take 2W + G.\n // So we have G/2 padding on each side to center them.\n const x = groupX + (col * slotWidth) + (CARD_GAP / 2);\n\n // Position cards from bottom of container, stacking upwards, starting at row 0 (bottom)\n const y = CANVAS_PADDING + contentHeight - BOTTOM_MARGIN - ((row + 1) * slotHeight);\n\n positions.set(id, {\n x,\n y,\n groupIndex,\n });\n }\n\n // Always use fixed bucket width\n bucketWidths.push(bucketWidth);\n\n // Advance position by fixed bucket width + spacing\n groupX += bucketWidth;\n if (groupIndex < grouping.groups.length - 1) {\n groupX += effectiveGroupSpacing;\n }\n }\n\n return {\n positions,\n totalWidth: groupX + CANVAS_PADDING,\n totalHeight: contentHeight + (CANVAS_PADDING * 2),\n bucketWidths,\n groupXs,\n };\n}\n"],"names":["CARD_GAP","CANVAS_PADDING"],"mappings":"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"}
|
|
@@ -18,7 +18,8 @@ function useCardSelection({ data, isPanning, selectedItem, zoomLevel, viewMode,
|
|
|
18
18
|
const selectedId = selectedItem
|
|
19
19
|
? (() => {
|
|
20
20
|
const index = data.indexOf(selectedItem);
|
|
21
|
-
|
|
21
|
+
const rawSelectedId = index !== -1 ? resolveId(selectedItem, index) : resolveId(selectedItem, 0);
|
|
22
|
+
return idResolution.normalizeIdToLayoutKey(rawSelectedId, layout);
|
|
22
23
|
})()
|
|
23
24
|
: null;
|
|
24
25
|
const cardPosition$1 = idResolution.getCardPositionFromLayout(itemId, layout, constants.BASE_CARD_WIDTH, constants.BASE_CARD_HEIGHT);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCardSelection.js","sources":["../../../../PivotViewer/hooks/useCardSelection.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 { useCallback } from 'react';\nimport { handleCardSelection } from '../utils/selection';\nimport type { Layout } from '../utils/cardPosition';\nimport type { ViewMode } from '../components/Toolbar';\nimport {\n getCardPositionFromLayout,\n normalizeIdToLayoutKey,\n type CardPosition,\n} from '../utils/idResolution';\nimport { createCardPositionCallbacks } from '../utils/cardPosition';\nimport { ZOOM_MAX, MIN_ZOOM_ON_SELECT, ZOOM_MULTIPLIER, BASE_CARD_WIDTH, BASE_CARD_HEIGHT } from '../utils/constants';\n\ninterface UseCardSelectionParams<TItem extends object> {\n data: TItem[];\n isPanning: boolean;\n selectedItem: TItem | null;\n zoomLevel: number;\n viewMode: ViewMode;\n layout: Layout;\n containerDimensions: { width: number; height: number };\n scrollPosition: { x: number; y: number };\n preSelectionState: { zoom: number; scrollLeft: number; scrollTop: number } | null;\n grouping: unknown;\n getItemId?: (item: TItem, index: number) => string | number;\n resolveId: (item: TItem, index: number) => string | number;\n setZoomLevel: (level: number) => void;\n setIsZooming: (zooming: boolean) => void;\n setSelectedItem: (item: TItem | null) => void;\n setPreSelectionState: (state: { zoom: number; scrollLeft: number; scrollTop: number } | null) => void;\n}\n\nexport function useCardSelection<TItem extends object>({\n data,\n isPanning,\n selectedItem,\n zoomLevel,\n viewMode,\n layout,\n containerDimensions,\n scrollPosition,\n preSelectionState,\n grouping,\n getItemId,\n resolveId,\n setZoomLevel,\n setIsZooming,\n setSelectedItem,\n setPreSelectionState,\n}: UseCardSelectionParams<TItem>) {\n return useCallback((item: TItem, e: MouseEvent, id?: number | string) => {\n if (isPanning) return;\n\n // Get container element from event target\n const container = (e.target as Element)?.closest('.pv-main')?.parentElement as HTMLDivElement | null;\n if (!container) return;\n\n // Resolve item ID\n let itemId = (id !== undefined && id !== null) ? id : resolveId(item, 0);\n itemId = normalizeIdToLayoutKey(itemId, layout);\n\n const selectedId = selectedItem\n ? (() => {\n const index = data.indexOf(selectedItem);\n
|
|
1
|
+
{"version":3,"file":"useCardSelection.js","sources":["../../../../PivotViewer/hooks/useCardSelection.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 { useCallback } from 'react';\nimport { handleCardSelection } from '../utils/selection';\nimport type { Layout } from '../utils/cardPosition';\nimport type { ViewMode } from '../components/Toolbar';\nimport {\n getCardPositionFromLayout,\n normalizeIdToLayoutKey,\n type CardPosition,\n} from '../utils/idResolution';\nimport { createCardPositionCallbacks } from '../utils/cardPosition';\nimport { ZOOM_MAX, MIN_ZOOM_ON_SELECT, ZOOM_MULTIPLIER, BASE_CARD_WIDTH, BASE_CARD_HEIGHT } from '../utils/constants';\n\ninterface UseCardSelectionParams<TItem extends object> {\n data: TItem[];\n isPanning: boolean;\n selectedItem: TItem | null;\n zoomLevel: number;\n viewMode: ViewMode;\n layout: Layout;\n containerDimensions: { width: number; height: number };\n scrollPosition: { x: number; y: number };\n preSelectionState: { zoom: number; scrollLeft: number; scrollTop: number } | null;\n grouping: unknown;\n getItemId?: (item: TItem, index: number) => string | number;\n resolveId: (item: TItem, index: number) => string | number;\n setZoomLevel: (level: number) => void;\n setIsZooming: (zooming: boolean) => void;\n setSelectedItem: (item: TItem | null) => void;\n setPreSelectionState: (state: { zoom: number; scrollLeft: number; scrollTop: number } | null) => void;\n}\n\nexport function useCardSelection<TItem extends object>({\n data,\n isPanning,\n selectedItem,\n zoomLevel,\n viewMode,\n layout,\n containerDimensions,\n scrollPosition,\n preSelectionState,\n grouping,\n getItemId,\n resolveId,\n setZoomLevel,\n setIsZooming,\n setSelectedItem,\n setPreSelectionState,\n}: UseCardSelectionParams<TItem>) {\n return useCallback((item: TItem, e: MouseEvent, id?: number | string) => {\n if (isPanning) return;\n\n // Get container element from event target\n const container = (e.target as Element)?.closest('.pv-main')?.parentElement as HTMLDivElement | null;\n if (!container) return;\n\n // Resolve item ID\n let itemId = (id !== undefined && id !== null) ? id : resolveId(item, 0);\n itemId = normalizeIdToLayoutKey(itemId, layout);\n\n const selectedId = selectedItem\n ? (() => {\n const index = data.indexOf(selectedItem);\n const rawSelectedId = index !== -1 ? resolveId(selectedItem, index) : resolveId(selectedItem, 0);\n return normalizeIdToLayoutKey(rawSelectedId, layout);\n })()\n : null;\n\n // Get card position from layout\n const cardPosition = getCardPositionFromLayout(itemId, layout, BASE_CARD_WIDTH, BASE_CARD_HEIGHT);\n\n // Calculate target position for animation\n let targetCardPosition: CardPosition | null = null;\n let callbacks = { getCardPositionAtZoom: null as unknown as ((zoom: number) => CardPosition | null), getLayoutSizeAtZoom: null as unknown as ((zoom: number) => { width: number; height: number }) };\n let targetTotalHeight = layout.totalHeight;\n\n if (viewMode === 'grouped' && cardPosition) {\n // Calculate target zoom\n const targetZoom = Math.min(ZOOM_MAX, Math.max(MIN_ZOOM_ON_SELECT, zoomLevel * ZOOM_MULTIPLIER));\n\n const targetContainerWidth = containerDimensions.width / targetZoom;\n const targetContainerHeight = containerDimensions.height;\n\n callbacks = createCardPositionCallbacks(\n itemId,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n grouping as unknown as any,\n viewMode,\n targetContainerWidth,\n targetContainerHeight,\n );\n\n const targetPosition = callbacks.getCardPositionAtZoom(targetZoom);\n if (targetPosition) {\n targetCardPosition = targetPosition;\n }\n\n const targetLayout = callbacks.getLayoutSizeAtZoom(targetZoom);\n targetTotalHeight = targetLayout.height;\n }\n\n handleCardSelection({\n item,\n itemId,\n selectedItemId: selectedId,\n container,\n cardPosition,\n targetCardPosition,\n getCardPositionAtZoom: callbacks.getCardPositionAtZoom,\n getLayoutSizeAtZoom: callbacks.getLayoutSizeAtZoom,\n spacer: container.querySelector('.pv-spacer') as HTMLDivElement,\n preSelectionState,\n startScrollPosition: { x: scrollPosition.x, y: scrollPosition.y },\n setZoomLevel,\n setIsZooming,\n setSelectedItem,\n setPreSelectionState,\n viewMode,\n zoomLevel,\n totalHeight: targetTotalHeight,\n });\n }, [isPanning, selectedItem, zoomLevel, preSelectionState, viewMode, resolveId, setZoomLevel, layout, grouping, containerDimensions, scrollPosition, data, getItemId]);\n}\n"],"names":["useCallback","normalizeIdToLayoutKey","cardPosition","getCardPositionFromLayout","BASE_CARD_WIDTH","BASE_CARD_HEIGHT","ZOOM_MAX","MIN_ZOOM_ON_SELECT","ZOOM_MULTIPLIER","createCardPositionCallbacks","handleCardSelection"],"mappings":"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"}
|
|
@@ -17,6 +17,9 @@ function useZoomState(initialZoom = 1) {
|
|
|
17
17
|
const handleZoomSlider = React.useCallback((e) => {
|
|
18
18
|
handleZoomChange(parseFloat(e.target.value));
|
|
19
19
|
}, [handleZoomChange]);
|
|
20
|
+
const handleZoomReset = React.useCallback(() => {
|
|
21
|
+
handleZoomChange(1);
|
|
22
|
+
}, [handleZoomChange]);
|
|
20
23
|
return {
|
|
21
24
|
zoomLevel,
|
|
22
25
|
setZoomLevel,
|
|
@@ -24,6 +27,7 @@ function useZoomState(initialZoom = 1) {
|
|
|
24
27
|
handleZoomIn,
|
|
25
28
|
handleZoomOut,
|
|
26
29
|
handleZoomSlider,
|
|
30
|
+
handleZoomReset,
|
|
27
31
|
};
|
|
28
32
|
}
|
|
29
33
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useZoomState.js","sources":["../../../../PivotViewer/hooks/useZoomState.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 { useState, useCallback } from 'react';\nimport { ZOOM_MIN, ZOOM_MAX } from '../utils/utils';\n\nexport function useZoomState(initialZoom = 1) {\n const [zoomLevel, setZoomLevel] = useState(initialZoom);\n\n const handleZoomChange = useCallback((newZoom: number) => {\n setZoomLevel(Math.max(ZOOM_MIN, Math.min(ZOOM_MAX, newZoom)));\n }, []);\n\n const handleZoomIn = useCallback(() => {\n handleZoomChange(zoomLevel + 0.2);\n }, [zoomLevel, handleZoomChange]);\n\n const handleZoomOut = useCallback(() => {\n handleZoomChange(zoomLevel - 0.2);\n }, [zoomLevel, handleZoomChange]);\n\n const handleZoomSlider = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n handleZoomChange(parseFloat(e.target.value));\n }, [handleZoomChange]);\n\n return {\n zoomLevel,\n setZoomLevel,\n handleZoomChange,\n handleZoomIn,\n handleZoomOut,\n handleZoomSlider,\n };\n}\n"],"names":["useState","useCallback","ZOOM_MIN","ZOOM_MAX"],"mappings":";;;;;AAMM,SAAU,YAAY,CAAC,WAAW,GAAG,CAAC,EAAA;IAC1C,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAGA,cAAQ,CAAC,WAAW,CAAC;AAEvD,IAAA,MAAM,gBAAgB,GAAGC,iBAAW,CAAC,CAAC,OAAe,KAAI;AACvD,QAAA,YAAY,CAAC,IAAI,CAAC,GAAG,CAACC,cAAQ,EAAE,IAAI,CAAC,GAAG,CAACC,cAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;IAC/D,CAAC,EAAE,EAAE,CAAC;AAEN,IAAA,MAAM,YAAY,GAAGF,iBAAW,CAAC,MAAK;AACpC,QAAA,gBAAgB,CAAC,SAAS,GAAG,GAAG,CAAC;AACnC,IAAA,CAAC,EAAE,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;AAEjC,IAAA,MAAM,aAAa,GAAGA,iBAAW,CAAC,MAAK;AACrC,QAAA,gBAAgB,CAAC,SAAS,GAAG,GAAG,CAAC;AACnC,IAAA,CAAC,EAAE,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;AAEjC,IAAA,MAAM,gBAAgB,GAAGA,iBAAW,CAAC,CAAC,CAAsC,KAAI;QAC9E,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC9C,IAAA,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC;IAEtB,OAAO;QACL,SAAS;QACT,YAAY;QACZ,gBAAgB;QAChB,YAAY;QACZ,aAAa;QACb,gBAAgB;
|
|
1
|
+
{"version":3,"file":"useZoomState.js","sources":["../../../../PivotViewer/hooks/useZoomState.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 { useState, useCallback } from 'react';\nimport { ZOOM_MIN, ZOOM_MAX } from '../utils/utils';\n\nexport function useZoomState(initialZoom = 1) {\n const [zoomLevel, setZoomLevel] = useState(initialZoom);\n\n const handleZoomChange = useCallback((newZoom: number) => {\n setZoomLevel(Math.max(ZOOM_MIN, Math.min(ZOOM_MAX, newZoom)));\n }, []);\n\n const handleZoomIn = useCallback(() => {\n handleZoomChange(zoomLevel + 0.2);\n }, [zoomLevel, handleZoomChange]);\n\n const handleZoomOut = useCallback(() => {\n handleZoomChange(zoomLevel - 0.2);\n }, [zoomLevel, handleZoomChange]);\n\n const handleZoomSlider = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n handleZoomChange(parseFloat(e.target.value));\n }, [handleZoomChange]);\n\n const handleZoomReset = useCallback(() => {\n handleZoomChange(1);\n }, [handleZoomChange]);\n\n return {\n zoomLevel,\n setZoomLevel,\n handleZoomChange,\n handleZoomIn,\n handleZoomOut,\n handleZoomSlider,\n handleZoomReset,\n };\n}\n"],"names":["useState","useCallback","ZOOM_MIN","ZOOM_MAX"],"mappings":";;;;;AAMM,SAAU,YAAY,CAAC,WAAW,GAAG,CAAC,EAAA;IAC1C,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAGA,cAAQ,CAAC,WAAW,CAAC;AAEvD,IAAA,MAAM,gBAAgB,GAAGC,iBAAW,CAAC,CAAC,OAAe,KAAI;AACvD,QAAA,YAAY,CAAC,IAAI,CAAC,GAAG,CAACC,cAAQ,EAAE,IAAI,CAAC,GAAG,CAACC,cAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;IAC/D,CAAC,EAAE,EAAE,CAAC;AAEN,IAAA,MAAM,YAAY,GAAGF,iBAAW,CAAC,MAAK;AACpC,QAAA,gBAAgB,CAAC,SAAS,GAAG,GAAG,CAAC;AACnC,IAAA,CAAC,EAAE,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;AAEjC,IAAA,MAAM,aAAa,GAAGA,iBAAW,CAAC,MAAK;AACrC,QAAA,gBAAgB,CAAC,SAAS,GAAG,GAAG,CAAC;AACnC,IAAA,CAAC,EAAE,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;AAEjC,IAAA,MAAM,gBAAgB,GAAGA,iBAAW,CAAC,CAAC,CAAsC,KAAI;QAC9E,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC9C,IAAA,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC;AAEtB,IAAA,MAAM,eAAe,GAAGA,iBAAW,CAAC,MAAK;QACvC,gBAAgB,CAAC,CAAC,CAAC;AACrB,IAAA,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC;IAEtB,OAAO;QACL,SAAS;QACT,YAAY;QACZ,gBAAgB;QAChB,YAAY;QACZ,aAAa;QACb,gBAAgB;QAChB,eAAe;KAChB;AACH;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sources":["../../../PivotViewer/types.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 { ReactNode } from 'react';\n\nexport type PivotPrimitive = string | number | boolean | Date | null | undefined;\n\n/**\n * Type-safe property accessor for accessing properties, including nested ones\n */\nexport type PropertyAccessor<TItem> = (item: TItem) => unknown;\n\n/**\n * Extract property path from a property accessor function\n * Supports nested properties like item => item.address.city\n */\nexport function getPropertyPath<TItem>(accessor: PropertyAccessor<TItem>): string {\n const fnStr = accessor.toString();\n // Match patterns like: item => item.prop or item => item.prop.nested or (item) => item.prop\n const match = fnStr.match(/(?:=>|return)\\s*[a-zA-Z_$][a-zA-Z0-9_$]*\\.([a-zA-Z_$][a-zA-Z0-9_$.]*)/);\n return match ? match[1] : '';\n}\n\n/**\n * Get the value from an item using a property path string\n * Supports nested properties like \"address.city\"\n */\nexport function getValueByPath<TItem>(item: TItem, path: string): unknown {\n const parts = path.split('.');\n let value: unknown = item;\n for (const part of parts) {\n if (value === null || value === undefined) {\n return undefined;\n }\n value = value[part];\n }\n return value;\n}\n\nexport interface PivotGroup<TItem extends object> {\n key: string;\n label: string;\n value: PivotPrimitive;\n items: TItem[];\n count?: number;\n}\n\nexport interface PivotDimension<TItem extends object> {\n key: string;\n label: string;\n getValue: (item: TItem) => PivotPrimitive;\n formatValue?: (value: PivotPrimitive) => string;\n sort?: (a: PivotGroup<TItem>, b: PivotGroup<TItem>) => number;\n}\n\nexport interface PivotFilterOption {\n key: string;\n label: string;\n value: PivotPrimitive;\n count: number;\n}\n\nexport interface PivotFilter<TItem extends object> {\n key: string;\n label: string;\n getValue: (item: TItem) => PivotPrimitive;\n multi?: boolean;\n options?: PivotFilterOption[];\n sort?: (a: PivotFilterOption, b: PivotFilterOption) => number;\n /** For numeric filters, enables range picker with histogram */\n type?: 'string' | 'number' | 'date';\n /** Number of buckets for the histogram in range filters */\n buckets?: number;\n}\n\nexport interface PivotViewerProps<TItem extends object> {\n data: TItem[];\n dimensions: PivotDimension<TItem>[];\n filters?: PivotFilter<TItem>[];\n defaultDimensionKey?: string;\n cardRenderer
|
|
1
|
+
{"version":3,"file":"types.js","sources":["../../../PivotViewer/types.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 { ReactNode } from 'react';\n\nexport type PivotPrimitive = string | number | boolean | Date | null | undefined;\n\n/**\n * Type-safe property accessor for accessing properties, including nested ones\n */\nexport type PropertyAccessor<TItem> = (item: TItem) => unknown;\n\n/**\n * Extract property path from a property accessor function\n * Supports nested properties like item => item.address.city\n */\nexport function getPropertyPath<TItem>(accessor: PropertyAccessor<TItem>): string {\n const fnStr = accessor.toString();\n // Match patterns like: item => item.prop or item => item.prop.nested or (item) => item.prop\n const match = fnStr.match(/(?:=>|return)\\s*[a-zA-Z_$][a-zA-Z0-9_$]*\\.([a-zA-Z_$][a-zA-Z0-9_$.]*)/);\n return match ? match[1] : '';\n}\n\n/**\n * Get the value from an item using a property path string\n * Supports nested properties like \"address.city\"\n */\nexport function getValueByPath<TItem>(item: TItem, path: string): unknown {\n const parts = path.split('.');\n let value: unknown = item;\n for (const part of parts) {\n if (value === null || value === undefined) {\n return undefined;\n }\n value = value[part];\n }\n return value;\n}\n\nexport interface PivotGroup<TItem extends object> {\n key: string;\n label: string;\n value: PivotPrimitive;\n items: TItem[];\n count?: number;\n}\n\nexport interface PivotDimension<TItem extends object> {\n key: string;\n label: string;\n getValue: (item: TItem) => PivotPrimitive;\n formatValue?: (value: PivotPrimitive) => string;\n sort?: (a: PivotGroup<TItem>, b: PivotGroup<TItem>) => number;\n}\n\nexport interface PivotFilterOption {\n key: string;\n label: string;\n value: PivotPrimitive;\n count: number;\n}\n\nexport interface PivotFilter<TItem extends object> {\n key: string;\n label: string;\n getValue: (item: TItem) => PivotPrimitive;\n multi?: boolean;\n options?: PivotFilterOption[];\n sort?: (a: PivotFilterOption, b: PivotFilterOption) => number;\n /** For numeric filters, enables range picker with histogram */\n type?: 'string' | 'number' | 'date';\n /** Number of buckets for the histogram in range filters */\n buckets?: number;\n}\n\nexport interface PivotViewerProps<TItem extends object> {\n data: TItem[];\n dimensions: PivotDimension<TItem>[];\n filters?: PivotFilter<TItem>[];\n defaultDimensionKey?: string;\n /** Renderer for card content; returns structured text data for display */\n cardRenderer: (item: TItem) => { title: string; labels?: string[]; values?: string[] };\n /** Optional renderer for the detail content area; the drawer shell (header/close/layout) stays component-owned */\n detailRenderer?: (item: TItem, onClose: () => void) => ReactNode;\n getItemId?: (item: TItem, index: number) => string | number;\n searchFields?: PropertyAccessor<TItem>[];\n className?: string;\n emptyContent?: ReactNode;\n isLoading?: boolean;\n /**\n * Optional color overrides mapped to PrimeReact-like CSS variables.\n * If omitted, values are taken from the global theme (PrimeReact defaults).\n */\n colors?: Partial<{\n primaryColor: string;\n primaryColorText: string;\n primary500: string;\n surfaceGround: string;\n surfaceCard: string;\n surfaceSection: string;\n surfaceOverlay: string;\n surfaceBorder: string;\n textColor: string;\n textColorSecondary: string;\n highlightBg: string;\n maskbg: string;\n focusRing: string;\n }>;\n}\n\nexport type FilterState = Record<string, Set<string>>;\n\nexport type RangeFilterState = Record<string, [number, number] | null>;\n"],"names":[],"mappings":";;AAgBM,SAAU,eAAe,CAAQ,QAAiC,EAAA;AACpE,IAAA,MAAM,KAAK,GAAG,QAAQ,CAAC,QAAQ,EAAE;IAEjC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,uEAAuE,CAAC;AAClG,IAAA,OAAO,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE;AAChC;AAMM,SAAU,cAAc,CAAQ,IAAW,EAAE,IAAY,EAAA;IAC3D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;IAC7B,IAAI,KAAK,GAAY,IAAI;AACzB,IAAA,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE;QACtB,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE;AACvC,YAAA,OAAO,SAAS;QACpB;AACA,QAAA,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC;IACvB;AACA,IAAA,OAAO,KAAK;AAChB;;;;;"}
|
|
@@ -107,7 +107,7 @@ function calculateCenterScrollPosition(container, cardPosition, zoomLevel, detai
|
|
|
107
107
|
const targetYCenter = viewportHeight / 2;
|
|
108
108
|
const targetYForBottom = viewportHeight * 0.7;
|
|
109
109
|
const scrollLeft = Math.max(0, cardCenterX - targetX);
|
|
110
|
-
|
|
110
|
+
const scrollTopForCenter = cardCenterY - targetYCenter;
|
|
111
111
|
const scrollTopForBottomVisible = cardBottomY - viewportHeight + 50;
|
|
112
112
|
let scrollTop = scrollTopForCenter;
|
|
113
113
|
if (scrollTopForCenter > scrollTopForBottomVisible + (cardPosition.height * zoomLevel / 2)) {
|