@griddle/core 0.1.9 → 0.1.10
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/dist/packing.d.ts +0 -9
- package/dist/packing.d.ts.map +1 -1
- package/dist/packing.js +0 -66
- package/dist/packing.js.map +1 -1
- package/dist/reflow.d.ts +1 -1
- package/dist/reflow.d.ts.map +1 -1
- package/dist/reflow.js +5 -76
- package/dist/reflow.js.map +1 -1
- package/package.json +1 -1
- package/src/packing.ts +0 -77
- package/src/reflow.ts +6 -96
package/dist/packing.d.ts
CHANGED
|
@@ -4,8 +4,6 @@ export interface PackTile {
|
|
|
4
4
|
w: number;
|
|
5
5
|
h: number;
|
|
6
6
|
}
|
|
7
|
-
export interface AnchoredPackTile extends PackTile, CellPos {
|
|
8
|
-
}
|
|
9
7
|
export interface PackComputation {
|
|
10
8
|
placements: Map<string, CellPos>;
|
|
11
9
|
/** Bounding box of the packed layout, in cells. */
|
|
@@ -15,11 +13,4 @@ export interface PackComputation {
|
|
|
15
13
|
holes: number;
|
|
16
14
|
}
|
|
17
15
|
export declare function computePack(tiles: PackTile[], maxCols: number): PackComputation | null;
|
|
18
|
-
/**
|
|
19
|
-
* Densely pack tiles around caller-owned anchors. Anchors are installed
|
|
20
|
-
* verbatim and never moved; remaining tiles use the same largest-first,
|
|
21
|
-
* top-left scan as Griddle's greedy pack fallback. This is the fixed-geometry
|
|
22
|
-
* counterpart to `computePack()` for layouts with deliberate placements.
|
|
23
|
-
*/
|
|
24
|
-
export declare function computePackAround(tiles: PackTile[], maxCols: number, anchors: AnchoredPackTile[]): PackComputation | null;
|
|
25
16
|
//# sourceMappingURL=packing.d.ts.map
|
package/dist/packing.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packing.d.ts","sourceRoot":"","sources":["../src/packing.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"packing.d.ts","sourceRoot":"","sources":["../src/packing.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAC;CACf;AAID,wBAAgB,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI,CAetF"}
|
package/dist/packing.js
CHANGED
|
@@ -32,72 +32,6 @@ export function computePack(tiles, maxCols) {
|
|
|
32
32
|
}
|
|
33
33
|
return greedyPack(tiles, Math.min(maxCols, area));
|
|
34
34
|
}
|
|
35
|
-
/**
|
|
36
|
-
* Densely pack tiles around caller-owned anchors. Anchors are installed
|
|
37
|
-
* verbatim and never moved; remaining tiles use the same largest-first,
|
|
38
|
-
* top-left scan as Griddle's greedy pack fallback. This is the fixed-geometry
|
|
39
|
-
* counterpart to `computePack()` for layouts with deliberate placements.
|
|
40
|
-
*/
|
|
41
|
-
export function computePackAround(tiles, maxCols, anchors) {
|
|
42
|
-
if ((tiles.length === 0 && anchors.length === 0) || maxCols <= 0)
|
|
43
|
-
return null;
|
|
44
|
-
const remaining = [...tiles].sort((a, b) => b.w * b.h - a.w * a.h || b.h - a.h);
|
|
45
|
-
const placements = new Map();
|
|
46
|
-
const occ = [];
|
|
47
|
-
const fits = (c, r, tw, th) => {
|
|
48
|
-
if (c < 0 || r < 0 || c + tw > maxCols)
|
|
49
|
-
return false;
|
|
50
|
-
for (let y = r; y < r + th; y++) {
|
|
51
|
-
const row = occ[y];
|
|
52
|
-
if (!row)
|
|
53
|
-
continue;
|
|
54
|
-
for (let x = c; x < c + tw; x++) {
|
|
55
|
-
if (row[x])
|
|
56
|
-
return false;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return true;
|
|
60
|
-
};
|
|
61
|
-
const mark = (c, r, tw, th) => {
|
|
62
|
-
for (let y = r; y < r + th; y++) {
|
|
63
|
-
let row = occ[y];
|
|
64
|
-
if (!row) {
|
|
65
|
-
row = new Array(maxCols).fill(false);
|
|
66
|
-
occ[y] = row;
|
|
67
|
-
}
|
|
68
|
-
for (let x = c; x < c + tw; x++)
|
|
69
|
-
row[x] = true;
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
for (const anchor of anchors) {
|
|
73
|
-
placements.set(anchor.id, { col: anchor.col, row: anchor.row });
|
|
74
|
-
mark(anchor.col, anchor.row, anchor.w, anchor.h);
|
|
75
|
-
}
|
|
76
|
-
let idx = 0;
|
|
77
|
-
while (remaining.length > 0) {
|
|
78
|
-
const col = idx % maxCols;
|
|
79
|
-
const row = (idx - col) / maxCols;
|
|
80
|
-
if (!occ[row]?.[col]) {
|
|
81
|
-
const tileIndex = remaining.findIndex((tile) => fits(col, row, tile.w, tile.h));
|
|
82
|
-
if (tileIndex >= 0) {
|
|
83
|
-
const tile = remaining.splice(tileIndex, 1)[0];
|
|
84
|
-
placements.set(tile.id, { col, row });
|
|
85
|
-
mark(col, row, tile.w, tile.h);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
idx++;
|
|
89
|
-
}
|
|
90
|
-
let width = 0;
|
|
91
|
-
let height = 0;
|
|
92
|
-
let area = 0;
|
|
93
|
-
for (const tile of [...anchors, ...tiles]) {
|
|
94
|
-
const placement = placements.get(tile.id);
|
|
95
|
-
width = Math.max(width, placement.col + tile.w);
|
|
96
|
-
height = Math.max(height, placement.row + tile.h);
|
|
97
|
-
area += tile.w * tile.h;
|
|
98
|
-
}
|
|
99
|
-
return { placements, width, height, holes: width * height - area };
|
|
100
|
-
}
|
|
101
35
|
/**
|
|
102
36
|
* Bounded backtracking tiler: every step covers the topmost-leftmost empty
|
|
103
37
|
* cell, trying each distinct unused tile size there. Returns null when no
|
package/dist/packing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packing.js","sourceRoot":"","sources":["../src/packing.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,EAAE;AACF,8EAA8E;AAC9E,0EAA0E;AAC1E,EAAE;AACF,yEAAyE;AACzE,kEAAkE;AAClE,8EAA8E;AAC9E,+CAA+C;AAC/C,2EAA2E;AAC3E,8EAA8E;AAC9E,0EAA0E;AAC1E,EAAE;AACF,2EAA2E;AAC3E,6EAA6E;
|
|
1
|
+
{"version":3,"file":"packing.js","sourceRoot":"","sources":["../src/packing.ts"],"names":[],"mappings":"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"}
|
package/dist/reflow.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CellRect, Tile } from './types.js';
|
|
2
2
|
/** Immutable identifier for a supported reflow algorithm. */
|
|
3
|
-
export type ReflowStrategy = '
|
|
3
|
+
export type ReflowStrategy = 'griddle-v1';
|
|
4
4
|
/** Options for a single explicit reflow operation. */
|
|
5
5
|
export interface ReflowOptions {
|
|
6
6
|
/** Positive finite target column count. */
|
package/dist/reflow.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reflow.d.ts","sourceRoot":"","sources":["../src/reflow.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"reflow.d.ts","sourceRoot":"","sources":["../src/reflow.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEjD,6DAA6D;AAC7D,MAAM,MAAM,cAAc,GAAG,YAAY,CAAC;AAE1C,sDAAsD;AACtD,MAAM,WAAW,aAAa;IAC5B,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,QAAQ,EAAE,cAAc,CAAC;IACzB,mEAAmE;IACnE,UAAU,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC;CACjD;AAwJD;;;GAGG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,SAAS,IAAI,EAAE,EACtB,OAAO,EAAE,aAAa,GACrB,IAAI,EAAE,CAMR"}
|
package/dist/reflow.js
CHANGED
|
@@ -4,25 +4,14 @@
|
|
|
4
4
|
// geometry where possible while adapting in-flow tiles to a finite column
|
|
5
5
|
// count. Strategy identifiers are immutable compatibility contracts.
|
|
6
6
|
import { rectsOverlap, tileRect } from './geometry.js';
|
|
7
|
-
import { computePack, computePackAround } from './packing.js';
|
|
8
7
|
function assertOptions(options) {
|
|
9
8
|
if (!Number.isFinite(options.cols) || !Number.isInteger(options.cols) || options.cols <= 0) {
|
|
10
9
|
throw new RangeError('Griddle: reflow cols must be a positive finite integer');
|
|
11
10
|
}
|
|
12
|
-
if (options.strategy !== '
|
|
11
|
+
if (options.strategy !== 'griddle-v1') {
|
|
13
12
|
throw new RangeError(`Griddle: unsupported reflow strategy "${String(options.strategy)}"`);
|
|
14
13
|
}
|
|
15
14
|
}
|
|
16
|
-
/**
|
|
17
|
-
* Match Griddle's finite-edge creation/resize behavior: trim an automatic
|
|
18
|
-
* tile's width to the available columns without changing its height.
|
|
19
|
-
*/
|
|
20
|
-
function trimTileToColumns(tile, cols) {
|
|
21
|
-
if (!Number.isInteger(tile.w) || tile.w <= 0 || !Number.isInteger(tile.h) || tile.h <= 0) {
|
|
22
|
-
throw new RangeError(`Griddle: tile "${tile.id}" footprint must use positive integer cells`);
|
|
23
|
-
}
|
|
24
|
-
return tile.w > cols ? { ...tile, w: cols } : { ...tile };
|
|
25
|
-
}
|
|
26
15
|
function scaleTileToFit(tile, cols) {
|
|
27
16
|
if (!Number.isInteger(tile.w) || tile.w <= 0 || !Number.isInteger(tile.h) || tile.h <= 0) {
|
|
28
17
|
throw new RangeError(`Griddle: tile "${tile.id}" footprint must use positive integer cells`);
|
|
@@ -110,7 +99,7 @@ function reflowWithPlacements(tiles, cols, placements) {
|
|
|
110
99
|
for (const tile of tiles) {
|
|
111
100
|
const placement = placements[tile.id];
|
|
112
101
|
if (placement) {
|
|
113
|
-
positioned.push(
|
|
102
|
+
positioned.push({ ...tile, ...placement });
|
|
114
103
|
}
|
|
115
104
|
else {
|
|
116
105
|
missing.push(scaleTileToFit(tile, cols));
|
|
@@ -128,60 +117,6 @@ function reflowWithPlacements(tiles, cols, placements) {
|
|
|
128
117
|
assertFiniteLayout(projected, cols);
|
|
129
118
|
return projected;
|
|
130
119
|
}
|
|
131
|
-
function applyPackedPositions(tiles, positions) {
|
|
132
|
-
return tiles.map((tile) => {
|
|
133
|
-
const position = positions.get(tile.id);
|
|
134
|
-
return position ? { ...tile, ...position } : { ...tile };
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Griddle-native automatic reflow. Unlike preserve-v1, this intentionally
|
|
139
|
-
* discards source gaps and positions, trims wide tiles like finite creation,
|
|
140
|
-
* and runs the dense exact/greedy packer used by `Grid.pack()`.
|
|
141
|
-
*/
|
|
142
|
-
function reflowGriddle(tiles, cols) {
|
|
143
|
-
const fitted = tiles.map((tile) => trimTileToColumns(tile, cols));
|
|
144
|
-
const packed = computePack(fitted.map(({ id, w, h }) => ({ id, w, h })), cols);
|
|
145
|
-
if (!packed)
|
|
146
|
-
return fitted;
|
|
147
|
-
const result = applyPackedPositions(fitted, packed.placements);
|
|
148
|
-
assertFiniteLayout(result, cols);
|
|
149
|
-
return result;
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Explicit placements are immutable anchors. Only unplaced tiles are trimmed
|
|
153
|
-
* and densely packed, using Griddle's greedy pack ordering around those
|
|
154
|
-
* anchors. Unknown placement ids are ignored.
|
|
155
|
-
*/
|
|
156
|
-
function reflowGriddleWithPlacements(tiles, cols, placements) {
|
|
157
|
-
const anchored = [];
|
|
158
|
-
const automatic = [];
|
|
159
|
-
for (const tile of tiles) {
|
|
160
|
-
const placement = placements[tile.id];
|
|
161
|
-
if (placement)
|
|
162
|
-
anchored.push({ ...tile, ...placement });
|
|
163
|
-
else
|
|
164
|
-
automatic.push(trimTileToColumns(tile, cols));
|
|
165
|
-
}
|
|
166
|
-
// User-authored placements are exact compatibility data: never trim, move,
|
|
167
|
-
// or silently resolve them. Invalid anchors reject the transaction.
|
|
168
|
-
assertFiniteLayout(anchored, cols);
|
|
169
|
-
const packed = computePackAround(automatic.map(({ id, w, h }) => ({ id, w, h })), cols, anchored.map(({ id, col, row, w, h }) => ({ id, col, row, w, h })));
|
|
170
|
-
if (!packed)
|
|
171
|
-
return anchored;
|
|
172
|
-
const anchoredById = new Map(anchored.map((tile) => [tile.id, tile]));
|
|
173
|
-
const automaticById = new Map(automatic.map((tile) => [tile.id, tile]));
|
|
174
|
-
const result = tiles.map((tile) => {
|
|
175
|
-
const anchor = anchoredById.get(tile.id);
|
|
176
|
-
if (anchor)
|
|
177
|
-
return { ...anchor };
|
|
178
|
-
const fitted = automaticById.get(tile.id);
|
|
179
|
-
const position = packed.placements.get(tile.id);
|
|
180
|
-
return { ...fitted, ...position };
|
|
181
|
-
});
|
|
182
|
-
assertFiniteLayout(result, cols);
|
|
183
|
-
return result;
|
|
184
|
-
}
|
|
185
120
|
/**
|
|
186
121
|
* Reflow tiles with an explicit immutable strategy. The input is never
|
|
187
122
|
* mutated, and every non-geometry tile property is preserved.
|
|
@@ -189,14 +124,8 @@ function reflowGriddleWithPlacements(tiles, cols, placements) {
|
|
|
189
124
|
export function reflowTiles(tiles, options) {
|
|
190
125
|
assertOptions(options);
|
|
191
126
|
const placements = options.placements;
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
: reflowWithoutPlacements(tiles, options.cols);
|
|
196
|
-
}
|
|
197
|
-
const hasMatchingPlacement = placements !== undefined && tiles.some((tile) => placements[tile.id] !== undefined);
|
|
198
|
-
return placements && hasMatchingPlacement
|
|
199
|
-
? reflowGriddleWithPlacements(tiles, options.cols, placements)
|
|
200
|
-
: reflowGriddle(tiles, options.cols);
|
|
127
|
+
return placements && Object.keys(placements).length > 0
|
|
128
|
+
? reflowWithPlacements(tiles, options.cols, placements)
|
|
129
|
+
: reflowWithoutPlacements(tiles, options.cols);
|
|
201
130
|
}
|
|
202
131
|
//# sourceMappingURL=reflow.js.map
|
package/dist/reflow.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reflow.js","sourceRoot":"","sources":["../src/reflow.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,EAAE;AACF,wEAAwE;AACxE,0EAA0E;AAC1E,qEAAqE;AAErE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"reflow.js","sourceRoot":"","sources":["../src/reflow.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/packing.ts
CHANGED
|
@@ -22,8 +22,6 @@ export interface PackTile {
|
|
|
22
22
|
h: number;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
export interface AnchoredPackTile extends PackTile, CellPos {}
|
|
26
|
-
|
|
27
25
|
export interface PackComputation {
|
|
28
26
|
placements: Map<string, CellPos>;
|
|
29
27
|
/** Bounding box of the packed layout, in cells. */
|
|
@@ -52,81 +50,6 @@ export function computePack(tiles: PackTile[], maxCols: number): PackComputation
|
|
|
52
50
|
return greedyPack(tiles, Math.min(maxCols, area));
|
|
53
51
|
}
|
|
54
52
|
|
|
55
|
-
/**
|
|
56
|
-
* Densely pack tiles around caller-owned anchors. Anchors are installed
|
|
57
|
-
* verbatim and never moved; remaining tiles use the same largest-first,
|
|
58
|
-
* top-left scan as Griddle's greedy pack fallback. This is the fixed-geometry
|
|
59
|
-
* counterpart to `computePack()` for layouts with deliberate placements.
|
|
60
|
-
*/
|
|
61
|
-
export function computePackAround(
|
|
62
|
-
tiles: PackTile[],
|
|
63
|
-
maxCols: number,
|
|
64
|
-
anchors: AnchoredPackTile[],
|
|
65
|
-
): PackComputation | null {
|
|
66
|
-
if ((tiles.length === 0 && anchors.length === 0) || maxCols <= 0) return null;
|
|
67
|
-
|
|
68
|
-
const remaining = [...tiles].sort(
|
|
69
|
-
(a, b) => b.w * b.h - a.w * a.h || b.h - a.h,
|
|
70
|
-
);
|
|
71
|
-
const placements = new Map<string, CellPos>();
|
|
72
|
-
const occ: boolean[][] = [];
|
|
73
|
-
|
|
74
|
-
const fits = (c: number, r: number, tw: number, th: number): boolean => {
|
|
75
|
-
if (c < 0 || r < 0 || c + tw > maxCols) return false;
|
|
76
|
-
for (let y = r; y < r + th; y++) {
|
|
77
|
-
const row = occ[y];
|
|
78
|
-
if (!row) continue;
|
|
79
|
-
for (let x = c; x < c + tw; x++) {
|
|
80
|
-
if (row[x]) return false;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return true;
|
|
84
|
-
};
|
|
85
|
-
const mark = (c: number, r: number, tw: number, th: number): void => {
|
|
86
|
-
for (let y = r; y < r + th; y++) {
|
|
87
|
-
let row = occ[y];
|
|
88
|
-
if (!row) {
|
|
89
|
-
row = new Array<boolean>(maxCols).fill(false);
|
|
90
|
-
occ[y] = row;
|
|
91
|
-
}
|
|
92
|
-
for (let x = c; x < c + tw; x++) row[x] = true;
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
|
|
96
|
-
for (const anchor of anchors) {
|
|
97
|
-
placements.set(anchor.id, { col: anchor.col, row: anchor.row });
|
|
98
|
-
mark(anchor.col, anchor.row, anchor.w, anchor.h);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
let idx = 0;
|
|
102
|
-
while (remaining.length > 0) {
|
|
103
|
-
const col = idx % maxCols;
|
|
104
|
-
const row = (idx - col) / maxCols;
|
|
105
|
-
if (!occ[row]?.[col]) {
|
|
106
|
-
const tileIndex = remaining.findIndex((tile) =>
|
|
107
|
-
fits(col, row, tile.w, tile.h),
|
|
108
|
-
);
|
|
109
|
-
if (tileIndex >= 0) {
|
|
110
|
-
const tile = remaining.splice(tileIndex, 1)[0]!;
|
|
111
|
-
placements.set(tile.id, { col, row });
|
|
112
|
-
mark(col, row, tile.w, tile.h);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
idx++;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
let width = 0;
|
|
119
|
-
let height = 0;
|
|
120
|
-
let area = 0;
|
|
121
|
-
for (const tile of [...anchors, ...tiles]) {
|
|
122
|
-
const placement = placements.get(tile.id)!;
|
|
123
|
-
width = Math.max(width, placement.col + tile.w);
|
|
124
|
-
height = Math.max(height, placement.row + tile.h);
|
|
125
|
-
area += tile.w * tile.h;
|
|
126
|
-
}
|
|
127
|
-
return { placements, width, height, holes: width * height - area };
|
|
128
|
-
}
|
|
129
|
-
|
|
130
53
|
/**
|
|
131
54
|
* Bounded backtracking tiler: every step covers the topmost-leftmost empty
|
|
132
55
|
* cell, trying each distinct unused tile size there. Returns null when no
|
package/src/reflow.ts
CHANGED
|
@@ -5,11 +5,10 @@
|
|
|
5
5
|
// count. Strategy identifiers are immutable compatibility contracts.
|
|
6
6
|
|
|
7
7
|
import { rectsOverlap, tileRect } from './geometry.js';
|
|
8
|
-
import { computePack, computePackAround } from './packing.js';
|
|
9
8
|
import type { CellRect, Tile } from './types.js';
|
|
10
9
|
|
|
11
10
|
/** Immutable identifier for a supported reflow algorithm. */
|
|
12
|
-
export type ReflowStrategy = '
|
|
11
|
+
export type ReflowStrategy = 'griddle-v1';
|
|
13
12
|
|
|
14
13
|
/** Options for a single explicit reflow operation. */
|
|
15
14
|
export interface ReflowOptions {
|
|
@@ -25,22 +24,11 @@ function assertOptions(options: ReflowOptions): void {
|
|
|
25
24
|
if (!Number.isFinite(options.cols) || !Number.isInteger(options.cols) || options.cols <= 0) {
|
|
26
25
|
throw new RangeError('Griddle: reflow cols must be a positive finite integer');
|
|
27
26
|
}
|
|
28
|
-
if (options.strategy !== '
|
|
27
|
+
if (options.strategy !== 'griddle-v1') {
|
|
29
28
|
throw new RangeError(`Griddle: unsupported reflow strategy "${String(options.strategy)}"`);
|
|
30
29
|
}
|
|
31
30
|
}
|
|
32
31
|
|
|
33
|
-
/**
|
|
34
|
-
* Match Griddle's finite-edge creation/resize behavior: trim an automatic
|
|
35
|
-
* tile's width to the available columns without changing its height.
|
|
36
|
-
*/
|
|
37
|
-
function trimTileToColumns(tile: Tile, cols: number): Tile {
|
|
38
|
-
if (!Number.isInteger(tile.w) || tile.w <= 0 || !Number.isInteger(tile.h) || tile.h <= 0) {
|
|
39
|
-
throw new RangeError(`Griddle: tile "${tile.id}" footprint must use positive integer cells`);
|
|
40
|
-
}
|
|
41
|
-
return tile.w > cols ? { ...tile, w: cols } : { ...tile };
|
|
42
|
-
}
|
|
43
|
-
|
|
44
32
|
function scaleTileToFit(tile: Tile, cols: number): Tile {
|
|
45
33
|
if (!Number.isInteger(tile.w) || tile.w <= 0 || !Number.isInteger(tile.h) || tile.h <= 0) {
|
|
46
34
|
throw new RangeError(`Griddle: tile "${tile.id}" footprint must use positive integer cells`);
|
|
@@ -157,7 +145,7 @@ function reflowWithPlacements(
|
|
|
157
145
|
for (const tile of tiles) {
|
|
158
146
|
const placement = placements[tile.id];
|
|
159
147
|
if (placement) {
|
|
160
|
-
positioned.push(
|
|
148
|
+
positioned.push({ ...tile, ...placement });
|
|
161
149
|
} else {
|
|
162
150
|
missing.push(scaleTileToFit(tile, cols));
|
|
163
151
|
}
|
|
@@ -182,77 +170,6 @@ function reflowWithPlacements(
|
|
|
182
170
|
return projected;
|
|
183
171
|
}
|
|
184
172
|
|
|
185
|
-
function applyPackedPositions(
|
|
186
|
-
tiles: readonly Tile[],
|
|
187
|
-
positions: ReadonlyMap<string, { col: number; row: number }>,
|
|
188
|
-
): Tile[] {
|
|
189
|
-
return tiles.map((tile) => {
|
|
190
|
-
const position = positions.get(tile.id);
|
|
191
|
-
return position ? { ...tile, ...position } : { ...tile };
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Griddle-native automatic reflow. Unlike preserve-v1, this intentionally
|
|
197
|
-
* discards source gaps and positions, trims wide tiles like finite creation,
|
|
198
|
-
* and runs the dense exact/greedy packer used by `Grid.pack()`.
|
|
199
|
-
*/
|
|
200
|
-
function reflowGriddle(tiles: readonly Tile[], cols: number): Tile[] {
|
|
201
|
-
const fitted = tiles.map((tile) => trimTileToColumns(tile, cols));
|
|
202
|
-
const packed = computePack(
|
|
203
|
-
fitted.map(({ id, w, h }) => ({ id, w, h })),
|
|
204
|
-
cols,
|
|
205
|
-
);
|
|
206
|
-
if (!packed) return fitted;
|
|
207
|
-
|
|
208
|
-
const result = applyPackedPositions(fitted, packed.placements);
|
|
209
|
-
assertFiniteLayout(result, cols);
|
|
210
|
-
return result;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Explicit placements are immutable anchors. Only unplaced tiles are trimmed
|
|
215
|
-
* and densely packed, using Griddle's greedy pack ordering around those
|
|
216
|
-
* anchors. Unknown placement ids are ignored.
|
|
217
|
-
*/
|
|
218
|
-
function reflowGriddleWithPlacements(
|
|
219
|
-
tiles: readonly Tile[],
|
|
220
|
-
cols: number,
|
|
221
|
-
placements: Readonly<Record<string, CellRect>>,
|
|
222
|
-
): Tile[] {
|
|
223
|
-
const anchored: Tile[] = [];
|
|
224
|
-
const automatic: Tile[] = [];
|
|
225
|
-
|
|
226
|
-
for (const tile of tiles) {
|
|
227
|
-
const placement = placements[tile.id];
|
|
228
|
-
if (placement) anchored.push({ ...tile, ...placement });
|
|
229
|
-
else automatic.push(trimTileToColumns(tile, cols));
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// User-authored placements are exact compatibility data: never trim, move,
|
|
233
|
-
// or silently resolve them. Invalid anchors reject the transaction.
|
|
234
|
-
assertFiniteLayout(anchored, cols);
|
|
235
|
-
|
|
236
|
-
const packed = computePackAround(
|
|
237
|
-
automatic.map(({ id, w, h }) => ({ id, w, h })),
|
|
238
|
-
cols,
|
|
239
|
-
anchored.map(({ id, col, row, w, h }) => ({ id, col, row, w, h })),
|
|
240
|
-
);
|
|
241
|
-
if (!packed) return anchored;
|
|
242
|
-
|
|
243
|
-
const anchoredById = new Map(anchored.map((tile) => [tile.id, tile]));
|
|
244
|
-
const automaticById = new Map(automatic.map((tile) => [tile.id, tile]));
|
|
245
|
-
const result = tiles.map((tile) => {
|
|
246
|
-
const anchor = anchoredById.get(tile.id);
|
|
247
|
-
if (anchor) return { ...anchor };
|
|
248
|
-
const fitted = automaticById.get(tile.id)!;
|
|
249
|
-
const position = packed.placements.get(tile.id)!;
|
|
250
|
-
return { ...fitted, ...position };
|
|
251
|
-
});
|
|
252
|
-
assertFiniteLayout(result, cols);
|
|
253
|
-
return result;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
173
|
/**
|
|
257
174
|
* Reflow tiles with an explicit immutable strategy. The input is never
|
|
258
175
|
* mutated, and every non-geometry tile property is preserved.
|
|
@@ -263,14 +180,7 @@ export function reflowTiles(
|
|
|
263
180
|
): Tile[] {
|
|
264
181
|
assertOptions(options);
|
|
265
182
|
const placements = options.placements;
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
: reflowWithoutPlacements(tiles, options.cols);
|
|
270
|
-
}
|
|
271
|
-
const hasMatchingPlacement =
|
|
272
|
-
placements !== undefined && tiles.some((tile) => placements[tile.id] !== undefined);
|
|
273
|
-
return placements && hasMatchingPlacement
|
|
274
|
-
? reflowGriddleWithPlacements(tiles, options.cols, placements)
|
|
275
|
-
: reflowGriddle(tiles, options.cols);
|
|
183
|
+
return placements && Object.keys(placements).length > 0
|
|
184
|
+
? reflowWithPlacements(tiles, options.cols, placements)
|
|
185
|
+
: reflowWithoutPlacements(tiles, options.cols);
|
|
276
186
|
}
|