@xtia/grid 0.2.0 → 0.4.0
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 +5 -5
- package/lib/grid.d.ts +31 -2
- package/lib/grid.js +101 -63
- package/lib/utils.js +1 -1
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ npm i @xtia/grid
|
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
```ts
|
|
25
|
-
import { Grid } from "@xtia/grid"; // ~
|
|
25
|
+
import { Grid } from "@xtia/grid"; // ~5.1kb gzipped (2.5kb + Pipe2D dep)
|
|
26
26
|
|
|
27
27
|
// initialise a 30x20 Grid<number> of 0's
|
|
28
28
|
const numGrid = Grid.solid(30, 20, 0);
|
|
@@ -115,11 +115,11 @@ spriteMap.set(1, 0, "forest.png"); // modify the view
|
|
|
115
115
|
console.log(world.get(1, 0)); // read the parent: "forest"
|
|
116
116
|
```
|
|
117
117
|
|
|
118
|
-
For one-way read-mapping, use `grid.
|
|
118
|
+
For one-way read-mapping, use `grid.values` - a [Pipe2D](https://github.com/tiadrop/pipe2d) view into the grid's data.
|
|
119
119
|
|
|
120
120
|
```ts
|
|
121
121
|
// create a one-way, player-centred sprite map
|
|
122
|
-
const viewport = world.
|
|
122
|
+
const viewport = world.values
|
|
123
123
|
.oob("mountain")
|
|
124
124
|
.map(t => t + ".png")
|
|
125
125
|
.crop(playerX - 5, playerY - 5, 10, 10);
|
|
@@ -138,7 +138,7 @@ const colourMap = new Map(Object.entries({
|
|
|
138
138
|
forest: C.x080,
|
|
139
139
|
mountain: C.xa70
|
|
140
140
|
}));
|
|
141
|
-
const minimap = world.
|
|
141
|
+
const minimap = world.values
|
|
142
142
|
.map(colourMap)
|
|
143
143
|
.floorCoordinates()
|
|
144
144
|
.crop(viewX, viewY, vw, vh)
|
|
@@ -236,7 +236,7 @@ We can perform batched updates, suppressing the 'change' event until a process c
|
|
|
236
236
|
Pipe2D makes it easy to save and restore grid data:
|
|
237
237
|
|
|
238
238
|
```ts
|
|
239
|
-
const snapshot = world.
|
|
239
|
+
const snapshot = world.values.stash();
|
|
240
240
|
|
|
241
241
|
const restored = Grid.init(snapshot);
|
|
242
242
|
// or paste it to an existing grid
|
package/lib/grid.d.ts
CHANGED
|
@@ -32,6 +32,31 @@ type CostFunc<T> = (cell: Cell<T>, context: {
|
|
|
32
32
|
traversalType: TraversalType;
|
|
33
33
|
from: Cell<T>;
|
|
34
34
|
}) => number;
|
|
35
|
+
type RectSpec = ({
|
|
36
|
+
left: number;
|
|
37
|
+
width: number;
|
|
38
|
+
right?: undefined;
|
|
39
|
+
} | {
|
|
40
|
+
left: number;
|
|
41
|
+
width?: undefined;
|
|
42
|
+
right: number;
|
|
43
|
+
} | {
|
|
44
|
+
left?: undefined;
|
|
45
|
+
width: number;
|
|
46
|
+
right: number;
|
|
47
|
+
}) & ({
|
|
48
|
+
top: number;
|
|
49
|
+
height: number;
|
|
50
|
+
bottom?: undefined;
|
|
51
|
+
} | {
|
|
52
|
+
top: number;
|
|
53
|
+
height?: undefined;
|
|
54
|
+
bottom: number;
|
|
55
|
+
} | {
|
|
56
|
+
top?: undefined;
|
|
57
|
+
height: number;
|
|
58
|
+
bottom: number;
|
|
59
|
+
});
|
|
35
60
|
export declare class Cell<T> {
|
|
36
61
|
readonly x: number;
|
|
37
62
|
readonly y: number;
|
|
@@ -57,8 +82,9 @@ export declare class Grid<T> {
|
|
|
57
82
|
private parentGet;
|
|
58
83
|
private parentSet;
|
|
59
84
|
private batch;
|
|
60
|
-
readonly cells: Pipe2D<Cell<T>>;
|
|
61
85
|
protected constructor(width: number, height: number, parentGet: GetXYFunc<T>, parentSet: (x: number, y: number, value: T) => void, batch: (cb: () => void) => void);
|
|
86
|
+
readonly cells: Pipe2D<Cell<T>>;
|
|
87
|
+
values: Pipe2D<T>;
|
|
62
88
|
pipe: Pipe2D<T>;
|
|
63
89
|
batchUpdate(fn: () => void): void;
|
|
64
90
|
get(x: number, y: number): T;
|
|
@@ -66,16 +92,19 @@ export declare class Grid<T> {
|
|
|
66
92
|
trySet(x: number, y: number, value: T): boolean;
|
|
67
93
|
fill(value: T): void;
|
|
68
94
|
paste(source: Source2D<T>, x?: number, y?: number): void;
|
|
95
|
+
paste(get: GetXYFunc<T>): void;
|
|
69
96
|
writeMask(mask: Source2D<boolean> | GetXYFunc<boolean>): Grid<T>;
|
|
70
97
|
[Symbol.iterator](): IterableIterator<T>;
|
|
71
98
|
forEach(callback: (value: T, x: number, y: number) => void): void;
|
|
72
|
-
map<U>(read: (initial: T, x: number, y: number) => U, write: (local: U, x: number, y: number) => T): Grid<U>;
|
|
99
|
+
map<U>(read: (initial: T, x: number, y: number) => U, write: ((local: U, x: number, y: number) => T)): Grid<U>;
|
|
73
100
|
region(x: number, y: number, width: number, height: number): Grid<T>;
|
|
101
|
+
region(rect: RectSpec): Grid<T>;
|
|
74
102
|
scroll(xDelta: number, yDelta: number, fill: T): this;
|
|
75
103
|
static init<T>(width: number, height: number, initCell: (x: number, y: number) => T): GridBase<T>;
|
|
76
104
|
static init<T>(source: Source2D<T>): GridBase<T>;
|
|
77
105
|
static solid<T>(width: number, height: number, fillValue: T): GridBase<T>;
|
|
78
106
|
static wrap<T>(width: number, height: number, get: (x: number, y: number) => T, set: (x: number, y: number, value: T) => void, batch?: (callback: () => void) => void): Grid<T>;
|
|
107
|
+
private assertValidCoordinates;
|
|
79
108
|
}
|
|
80
109
|
export declare class GridBase<T> extends Grid<T> {
|
|
81
110
|
private data;
|
package/lib/grid.js
CHANGED
|
@@ -6,7 +6,12 @@ export var TraversalType;
|
|
|
6
6
|
TraversalType[TraversalType["diagonal"] = 1] = "diagonal";
|
|
7
7
|
TraversalType[TraversalType["shortcut"] = 2] = "shortcut";
|
|
8
8
|
})(TraversalType || (TraversalType = {}));
|
|
9
|
+
const cardinalOffsets = [[-1, 0], [1, 0], [0, -1], [0, 1]];
|
|
10
|
+
const allOffsets = [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]];
|
|
9
11
|
export class Cell {
|
|
12
|
+
x;
|
|
13
|
+
y;
|
|
14
|
+
gridView;
|
|
10
15
|
constructor(x, y, gridView) {
|
|
11
16
|
this.x = x;
|
|
12
17
|
this.y = y;
|
|
@@ -36,12 +41,11 @@ export class Cell {
|
|
|
36
41
|
}
|
|
37
42
|
getNeighbours(includeDiagonals = false) {
|
|
38
43
|
const offsets = includeDiagonals
|
|
39
|
-
?
|
|
40
|
-
:
|
|
44
|
+
? allOffsets
|
|
45
|
+
: cardinalOffsets;
|
|
41
46
|
return offsets
|
|
42
|
-
.map(
|
|
43
|
-
.filter(
|
|
44
|
-
.map(([tx, ty]) => this.gridView.cells.get(tx, ty));
|
|
47
|
+
.map(o => this.look(o[0], o[1]))
|
|
48
|
+
.filter(v => v);
|
|
45
49
|
}
|
|
46
50
|
look(xDelta, yDelta) {
|
|
47
51
|
const [x, y] = [this.x + xDelta, this.y + yDelta];
|
|
@@ -50,8 +54,11 @@ export class Cell {
|
|
|
50
54
|
return this.gridView.cells.get(xDelta + this.x, yDelta + this.y);
|
|
51
55
|
}
|
|
52
56
|
findPath(target, getCost, options = {}) {
|
|
53
|
-
const pathMap = this.calculateCosts(getCost,
|
|
54
|
-
|
|
57
|
+
const pathMap = this.calculateCosts(getCost, {
|
|
58
|
+
...options,
|
|
59
|
+
stopAt: target,
|
|
60
|
+
}, true);
|
|
61
|
+
return pathMap?.get(...this.getSiblingXY(target));
|
|
55
62
|
}
|
|
56
63
|
getPathMap(getCost, options = {}) {
|
|
57
64
|
return this.calculateCosts(getCost, options, true);
|
|
@@ -60,16 +67,14 @@ export class Cell {
|
|
|
60
67
|
return this.calculateCosts(getCost, options);
|
|
61
68
|
}
|
|
62
69
|
calculateCosts(getCost, options, asPathMap = false) {
|
|
63
|
-
var _a, _b;
|
|
64
|
-
var _c;
|
|
65
70
|
const visited = new Set();
|
|
66
71
|
const costs = new Map();
|
|
67
|
-
const maxCost =
|
|
72
|
+
const maxCost = options.maxCost ?? Infinity;
|
|
68
73
|
const pathInfo = asPathMap
|
|
69
74
|
? new Map()
|
|
70
75
|
: null;
|
|
71
76
|
const getCostFn = getCost instanceof Map
|
|
72
|
-
? (cell) =>
|
|
77
|
+
? (cell) => getCost.get(cell.value) ?? Infinity
|
|
73
78
|
: getCost;
|
|
74
79
|
costs.set(this, 0);
|
|
75
80
|
const queue = new OrderedQueue([this, 0]);
|
|
@@ -79,7 +84,7 @@ export class Cell {
|
|
|
79
84
|
if (visited.has(current))
|
|
80
85
|
continue;
|
|
81
86
|
visited.add(current);
|
|
82
|
-
|
|
87
|
+
options.onVisit?.({ cell: current, cost: costs.get(current) });
|
|
83
88
|
if (stopAtCell && current === stopAtCell) {
|
|
84
89
|
break;
|
|
85
90
|
}
|
|
@@ -92,7 +97,7 @@ export class Cell {
|
|
|
92
97
|
}));
|
|
93
98
|
const shortcutCells = typeof options.shortcutMap == "function"
|
|
94
99
|
? options.shortcutMap(current.x, current.y)
|
|
95
|
-
:
|
|
100
|
+
: options.shortcutMap?.get(current.x, current.y);
|
|
96
101
|
if (shortcutCells) {
|
|
97
102
|
const shortcuts = shortcutCells.map(loc => this.getSiblingCell(loc)).map(cell => ({
|
|
98
103
|
traversalType: TraversalType.shortcut,
|
|
@@ -101,7 +106,6 @@ export class Cell {
|
|
|
101
106
|
neighbours.push(...shortcuts);
|
|
102
107
|
}
|
|
103
108
|
neighbours.forEach(n => {
|
|
104
|
-
var _a;
|
|
105
109
|
if (visited.has(n.cell))
|
|
106
110
|
return;
|
|
107
111
|
const moveCost = getCostFn(n.cell, {
|
|
@@ -111,10 +115,10 @@ export class Cell {
|
|
|
111
115
|
if (moveCost === Infinity)
|
|
112
116
|
return;
|
|
113
117
|
const newCost = currentCost + moveCost;
|
|
114
|
-
const oldCost =
|
|
118
|
+
const oldCost = costs.get(n.cell) ?? Infinity;
|
|
115
119
|
if (newCost < oldCost && newCost <= maxCost) {
|
|
116
120
|
costs.set(n.cell, newCost);
|
|
117
|
-
pathInfo
|
|
121
|
+
pathInfo?.set(n.cell, current);
|
|
118
122
|
queue.add(n.cell, newCost);
|
|
119
123
|
}
|
|
120
124
|
});
|
|
@@ -181,9 +185,8 @@ export class Cell {
|
|
|
181
185
|
}
|
|
182
186
|
}
|
|
183
187
|
createVisibilityMap(isClear, options = {}) {
|
|
184
|
-
var _a;
|
|
185
188
|
const maxDistance = options.maxDistance;
|
|
186
|
-
const boundariesVisible =
|
|
189
|
+
const boundariesVisible = options.boundariesVisible ?? true;
|
|
187
190
|
return new Pipe2D(this.gridView.width, this.gridView.height, (x, y) => {
|
|
188
191
|
if (!isClear(this)) {
|
|
189
192
|
return x === this.x && y === this.y ? boundariesVisible : false;
|
|
@@ -208,76 +211,73 @@ function getDistance(c1, c2) {
|
|
|
208
211
|
return Math.sqrt(Math.pow(c2.x - c1.x, 2) + Math.pow(c2.y - c1.y, 2));
|
|
209
212
|
}
|
|
210
213
|
export class Grid {
|
|
214
|
+
width;
|
|
215
|
+
height;
|
|
216
|
+
parentGet;
|
|
217
|
+
parentSet;
|
|
218
|
+
batch;
|
|
211
219
|
constructor(width, height, parentGet, parentSet, batch) {
|
|
212
220
|
this.width = width;
|
|
213
221
|
this.height = height;
|
|
214
222
|
this.parentGet = parentGet;
|
|
215
223
|
this.parentSet = parentSet;
|
|
216
224
|
this.batch = batch;
|
|
217
|
-
|
|
218
|
-
|
|
225
|
+
if (!Number.isInteger(width) || !Number.isInteger(height) || width < 0 || height < 0) {
|
|
226
|
+
throw new Error(`Grid width & height must be non-negative integers; got (${width} x ${height})`);
|
|
227
|
+
}
|
|
228
|
+
this.cells = new Pipe2D(width, height, (x, y) => {
|
|
229
|
+
if (x < 0 || x >= width || y < 0 || y >= height || !Number.isInteger(x) || !Number.isInteger(y)) {
|
|
219
230
|
throw new RangeError(`Cell coordinates must be bounded integers; got (${x}, ${y})`);
|
|
220
231
|
}
|
|
221
232
|
return new Cell(x, y, this);
|
|
222
|
-
}).
|
|
223
|
-
this.pipe = new Pipe2D(this);
|
|
224
|
-
if (!Number.isInteger(width) || !Number.isInteger(height)) {
|
|
225
|
-
throw new Error(`Grid width & height must be integer; got (${width} x ${height})`);
|
|
226
|
-
}
|
|
227
|
-
if (width < 0 || height < 0) {
|
|
228
|
-
throw new Error(`Grid width/height may not be less than 0; got (${width} x ${height})`);
|
|
229
|
-
}
|
|
233
|
+
}).withCache();
|
|
230
234
|
}
|
|
235
|
+
cells;
|
|
236
|
+
values = new Pipe2D(this);
|
|
237
|
+
pipe = this.values;
|
|
231
238
|
batchUpdate(fn) {
|
|
232
239
|
this.batch(fn);
|
|
233
240
|
}
|
|
234
241
|
get(x, y) {
|
|
235
|
-
|
|
236
|
-
throw new Error(`Coordinates must be integer; got (${x}, ${y})`);
|
|
237
|
-
}
|
|
238
|
-
if (x < 0 || x >= this.width || y < 0 || y >= this.height) {
|
|
239
|
-
throw new RangeError("Coordinates out of bounds");
|
|
240
|
-
}
|
|
242
|
+
this.assertValidCoordinates(x, y);
|
|
241
243
|
return this.parentGet(x, y);
|
|
242
244
|
}
|
|
243
245
|
set(x, y, value) {
|
|
244
|
-
|
|
245
|
-
throw new Error(`Coordinates must be integer; got (${x}, ${y})`);
|
|
246
|
-
}
|
|
247
|
-
if (x < 0 || x >= this.width || y < 0 || y >= this.height) {
|
|
248
|
-
throw new RangeError("Coordinates out of bounds");
|
|
249
|
-
}
|
|
246
|
+
this.assertValidCoordinates(x, y);
|
|
250
247
|
this.parentSet(x, y, value);
|
|
251
248
|
}
|
|
252
249
|
trySet(x, y, value) {
|
|
253
250
|
if (x < 0
|
|
254
251
|
|| x >= this.width
|
|
255
252
|
|| y < 0
|
|
256
|
-
|| y >= this.height
|
|
257
|
-
|| !Number.isInteger(x)
|
|
258
|
-
|| !Number.isInteger(y))
|
|
253
|
+
|| y >= this.height)
|
|
259
254
|
return false;
|
|
260
|
-
this.
|
|
255
|
+
this.parentSet(x, y, value);
|
|
261
256
|
return true;
|
|
262
257
|
}
|
|
263
258
|
fill(value) {
|
|
264
259
|
this.batchUpdate(() => {
|
|
265
260
|
for (let y = 0; y < this.height; y++) {
|
|
266
261
|
for (let x = 0; x < this.width; x++) {
|
|
267
|
-
this.
|
|
262
|
+
this.parentSet(x, y, value);
|
|
268
263
|
}
|
|
269
264
|
}
|
|
270
265
|
});
|
|
271
266
|
}
|
|
272
|
-
paste(
|
|
273
|
-
|
|
267
|
+
paste(_source, x = 0, y = 0) {
|
|
268
|
+
this.assertValidCoordinates(x, y, true);
|
|
269
|
+
const source = typeof _source == "function"
|
|
270
|
+
? new Pipe2D(this.width, this.height, _source)
|
|
271
|
+
: _source;
|
|
272
|
+
const sourcePipe = source instanceof Pipe2D ? source : new Pipe2D(source);
|
|
273
|
+
const cachedSource = sourcePipe.stash();
|
|
274
274
|
this.batchUpdate(() => {
|
|
275
275
|
for (let oy = 0; oy < source.height; oy++) {
|
|
276
276
|
for (let ox = 0; ox < source.width; ox++) {
|
|
277
277
|
const tx = ox + x, ty = oy + y;
|
|
278
278
|
if (tx < 0 || tx >= this.width || ty < 0 || ty >= this.height)
|
|
279
279
|
continue;
|
|
280
|
-
this.
|
|
280
|
+
this.parentSet(tx, ty, cachedSource.get(ox, oy));
|
|
281
281
|
}
|
|
282
282
|
}
|
|
283
283
|
});
|
|
@@ -287,10 +287,15 @@ export class Grid {
|
|
|
287
287
|
? mask
|
|
288
288
|
: (x, y) => mask.get(x, y);
|
|
289
289
|
return new Grid(this.width, this.height, this.parentGet, (x, y, v) => {
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
290
|
+
try {
|
|
291
|
+
const writable = getMask(x, y);
|
|
292
|
+
if (!writable)
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
catch (e) {
|
|
296
|
+
throw new Error(`Failed to read write-mask at (${x}, ${y})`, { cause: e });
|
|
293
297
|
}
|
|
298
|
+
this.parentSet(x, y, v);
|
|
294
299
|
}, cb => this.batch(cb));
|
|
295
300
|
}
|
|
296
301
|
*[Symbol.iterator]() {
|
|
@@ -310,12 +315,39 @@ export class Grid {
|
|
|
310
315
|
map(read, write) {
|
|
311
316
|
return new Grid(this.width, this.height, (x, y) => read(this.parentGet(x, y), x, y), (x, y, value) => this.parentSet(x, y, write(value, x, y)), fn => this.batch(fn));
|
|
312
317
|
}
|
|
313
|
-
region(
|
|
314
|
-
|
|
315
|
-
|
|
318
|
+
region(xOrRect, y = 0, width = 0, height = 0) {
|
|
319
|
+
let x;
|
|
320
|
+
if (typeof xOrRect == "number") {
|
|
321
|
+
x = xOrRect;
|
|
322
|
+
}
|
|
323
|
+
else {
|
|
324
|
+
if (xOrRect.left === undefined) {
|
|
325
|
+
width = xOrRect.width;
|
|
326
|
+
x = (this.width - 1 - xOrRect.right) - width + 1;
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
x = xOrRect.left;
|
|
330
|
+
width = xOrRect.width === undefined
|
|
331
|
+
? (this.width - 1 - xOrRect.right) - x + 1
|
|
332
|
+
: xOrRect.width;
|
|
333
|
+
}
|
|
334
|
+
if (xOrRect.top === undefined) {
|
|
335
|
+
height = xOrRect.height;
|
|
336
|
+
y = (this.height - 1 - xOrRect.bottom) - height + 1;
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
y = xOrRect.top;
|
|
340
|
+
height = xOrRect.height === undefined
|
|
341
|
+
? (this.height - 1 - xOrRect.bottom) - y + 1
|
|
342
|
+
: xOrRect.height;
|
|
343
|
+
}
|
|
316
344
|
}
|
|
317
|
-
|
|
318
|
-
|
|
345
|
+
this.assertValidCoordinates(x, y);
|
|
346
|
+
if (!Number.isInteger(width) || !Number.isInteger(height)) {
|
|
347
|
+
throw new Error("Region dimensions must be integer");
|
|
348
|
+
}
|
|
349
|
+
if (x + width > this.width || y + height > this.height) {
|
|
350
|
+
throw new RangeError("Requested region exceeds the parent's bounds");
|
|
319
351
|
}
|
|
320
352
|
return new Grid(width, height, (tx, ty) => {
|
|
321
353
|
return this.parentGet(tx + x, ty + y);
|
|
@@ -324,9 +356,7 @@ export class Grid {
|
|
|
324
356
|
}, fn => this.batch(fn));
|
|
325
357
|
}
|
|
326
358
|
scroll(xDelta, yDelta, fill) {
|
|
327
|
-
|
|
328
|
-
throw new Error(`Scroll offsets must be integer; got (${xDelta}, ${yDelta})`);
|
|
329
|
-
}
|
|
359
|
+
this.assertValidCoordinates(xDelta, yDelta, true);
|
|
330
360
|
this.paste(this, xDelta, yDelta);
|
|
331
361
|
if (xDelta > 0) {
|
|
332
362
|
this.region(0, 0, xDelta, this.height).fill(fill);
|
|
@@ -357,12 +387,22 @@ export class Grid {
|
|
|
357
387
|
static wrap(width, height, get, set, batch = cb => cb()) {
|
|
358
388
|
return new Grid(width, height, get, set, batch);
|
|
359
389
|
}
|
|
390
|
+
assertValidCoordinates(x, y, ignoreBounds = false) {
|
|
391
|
+
if (!Number.isInteger(x) || !Number.isInteger(y)) {
|
|
392
|
+
throw new Error(`Coordinates must be integer; got (${x}, ${y})`);
|
|
393
|
+
}
|
|
394
|
+
if (!ignoreBounds && (x < 0 || x >= this.width || y < 0 || y >= this.height)) {
|
|
395
|
+
throw new RangeError(`Coordinates out of bounds (${x}, ${y}) / (${this.width}, ${this.height})`);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
360
398
|
}
|
|
361
399
|
export class GridBase extends Grid {
|
|
400
|
+
data;
|
|
401
|
+
eventHandlers = {};
|
|
362
402
|
triggerEvent(name, data) {
|
|
363
|
-
|
|
364
|
-
(_a = this.eventHandlers[name]) === null || _a === void 0 ? void 0 : _a.forEach(obj => obj.fn(data));
|
|
403
|
+
this.eventHandlers[name]?.forEach(obj => obj.fn(data));
|
|
365
404
|
}
|
|
405
|
+
batchState = null;
|
|
366
406
|
batchUpdate(fn) {
|
|
367
407
|
if (this.batchState) {
|
|
368
408
|
this.batchState.level++;
|
|
@@ -384,8 +424,6 @@ export class GridBase extends Grid {
|
|
|
384
424
|
}
|
|
385
425
|
constructor(source) {
|
|
386
426
|
super(source.width, source.height, (x, y) => this.data[y * this.width + x], (x, y, value) => this._set(x, y, value), fn => this.batchUpdate(fn));
|
|
387
|
-
this.eventHandlers = {};
|
|
388
|
-
this.batchState = null;
|
|
389
427
|
const sourcePipe = source instanceof Pipe2D
|
|
390
428
|
? source
|
|
391
429
|
: new Pipe2D(source);
|
package/lib/utils.js
CHANGED
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "0.
|
|
2
|
+
"version": "0.4.0",
|
|
3
3
|
"description": "2D store and utilities, with zero-copy regions and transform layers, pathfinding, Pipe2D interop",
|
|
4
4
|
"name": "@xtia/grid",
|
|
5
5
|
"exports": {
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"files": [
|
|
22
22
|
"lib/"
|
|
23
23
|
],
|
|
24
|
+
"license": "MIT",
|
|
24
25
|
"devDependencies": {
|
|
25
26
|
"@vitest/coverage-v8": "^4.1.10",
|
|
26
27
|
"typescript": "^7.0.2",
|