@mapka/shelf-pack 0.4.1 → 0.4.3
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/lib/.buildInfo.json +1 -1
- package/lib/index.d.ts +46 -80
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +356 -355
- package/lib/index.js.map +1 -1
- package/package.json +2 -2
- package/src/index.js +374 -378
package/lib/index.js
CHANGED
|
@@ -1,29 +1,3 @@
|
|
|
1
|
-
export default ShelfPack;
|
|
2
|
-
/**
|
|
3
|
-
* Create a new ShelfPack bin allocator.
|
|
4
|
-
*
|
|
5
|
-
* Uses the Shelf Best Height Fit algorithm from
|
|
6
|
-
* http://clb.demon.fi/files/RectangleBinPack.pdf
|
|
7
|
-
*
|
|
8
|
-
* @class ShelfPack
|
|
9
|
-
* @param {number} [w=64] Initial width of the sprite
|
|
10
|
-
* @param {number} [h=64] Initial width of the sprite
|
|
11
|
-
* @param {Object} [options]
|
|
12
|
-
* @param {boolean} [options.autoResize=false] If `true`, the sprite will automatically grow
|
|
13
|
-
* @example
|
|
14
|
-
* var sprite = new ShelfPack(64, 64, { autoResize: false });
|
|
15
|
-
*/
|
|
16
|
-
function ShelfPack(w, h, options) {
|
|
17
|
-
options = options || {};
|
|
18
|
-
this.w = w || 64;
|
|
19
|
-
this.h = h || 64;
|
|
20
|
-
this.autoResize = !!options.autoResize;
|
|
21
|
-
this.shelves = [];
|
|
22
|
-
this.freebins = [];
|
|
23
|
-
this.stats = {};
|
|
24
|
-
this.bins = {};
|
|
25
|
-
this.maxId = 0;
|
|
26
|
-
}
|
|
27
1
|
/**
|
|
28
2
|
* Bin object with `id`, `width`, `height` properties
|
|
29
3
|
* @typedef {Object} BinShorthand
|
|
@@ -32,374 +6,401 @@ function ShelfPack(w, h, options) {
|
|
|
32
6
|
* @property {number} h Height of the bin
|
|
33
7
|
*/
|
|
34
8
|
/**
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* @property {number} height Height of the bin
|
|
40
|
-
*/
|
|
41
|
-
/**
|
|
42
|
-
* Batch pack multiple bins into the sprite.
|
|
9
|
+
* Create a new ShelfPack bin allocator.
|
|
10
|
+
*
|
|
11
|
+
* Uses the Shelf Best Height Fit algorithm from
|
|
12
|
+
* http://clb.demon.fi/files/RectangleBinPack.pdf
|
|
43
13
|
*
|
|
44
|
-
* @param {Object[]} bins Array of requested bins - each object should have `width`, `height` (or `w`, `h`) properties
|
|
45
|
-
* @param {Object} [options]
|
|
46
|
-
* @param {boolean} [options.inPlace=false] If `true`, the supplied bin objects will be updated inplace with `x` and `y` properties
|
|
47
|
-
* @returns {Bin[]} Array of allocated Bins - each Bin is an object with `id`, `x`, `y`, `w`, `h` properties
|
|
48
|
-
* @noto Mutate input bins
|
|
49
14
|
* @example
|
|
50
|
-
* var
|
|
51
|
-
* { id: 1, w: 12, h: 12 },
|
|
52
|
-
* { id: 2, w: 12, h: 16 },
|
|
53
|
-
* { id: 3, w: 12, h: 24 }
|
|
54
|
-
* ];
|
|
55
|
-
* var results = sprite.pack(bins, { inPlace: false });
|
|
15
|
+
* var sprite = new ShelfPack(64, 64, { autoResize: false });
|
|
56
16
|
*/
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
17
|
+
export default class ShelfPack {
|
|
18
|
+
/**
|
|
19
|
+
* @param {number} [w=64] Initial width of the sprite
|
|
20
|
+
* @param {number} [h=64] Initial width of the sprite
|
|
21
|
+
* @param {Object} [options]
|
|
22
|
+
* @param {boolean} [options.autoResize=false] If `true`, the sprite will automatically grow
|
|
23
|
+
*/
|
|
24
|
+
constructor(w, h, options) {
|
|
25
|
+
options = options || {};
|
|
26
|
+
this.w = w || 64;
|
|
27
|
+
this.h = h || 64;
|
|
28
|
+
this.autoResize = !!options.autoResize;
|
|
29
|
+
this.shelves = [];
|
|
30
|
+
this.freebins = [];
|
|
31
|
+
this.stats = {};
|
|
32
|
+
this.bins = {};
|
|
33
|
+
this.maxId = 0;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Batch pack multiple bins into the sprite.
|
|
37
|
+
*
|
|
38
|
+
* @param {Object[]} bins Array of requested bins - each object should have `width`, `height` (or `w`, `h`) properties
|
|
39
|
+
* @param {Object} [options]
|
|
40
|
+
* @param {boolean} [options.inPlace=false] If `true`, the supplied bin objects will be updated inplace with `x` and `y` properties
|
|
41
|
+
* @returns {Bin[]} Array of allocated Bins - each Bin is an object with `id`, `x`, `y`, `w`, `h` properties
|
|
42
|
+
* @noto Mutate input bins
|
|
43
|
+
* @example
|
|
44
|
+
* var bins = [
|
|
45
|
+
* { id: 1, w: 12, h: 12 },
|
|
46
|
+
* { id: 2, w: 12, h: 16 },
|
|
47
|
+
* { id: 3, w: 12, h: 24 }
|
|
48
|
+
* ];
|
|
49
|
+
* var results = sprite.pack(bins, { inPlace: false });
|
|
50
|
+
*/
|
|
51
|
+
pack(bins, options) {
|
|
52
|
+
bins = [].concat(bins);
|
|
53
|
+
options = options || {};
|
|
54
|
+
var results = [], w, h, id, allocation;
|
|
55
|
+
for (var i = 0; i < bins.length; i++) {
|
|
56
|
+
w = bins[i].w || bins[i].width;
|
|
57
|
+
h = bins[i].h || bins[i].height;
|
|
58
|
+
id = bins[i].id;
|
|
59
|
+
if (w && h) {
|
|
60
|
+
allocation = this.packOne(w, h, id);
|
|
61
|
+
if (!allocation) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (options.inPlace) {
|
|
65
|
+
bins[i].x = allocation.x;
|
|
66
|
+
bins[i].y = allocation.y;
|
|
67
|
+
bins[i].id = allocation.id;
|
|
68
|
+
}
|
|
69
|
+
results.push(allocation);
|
|
74
70
|
}
|
|
75
|
-
results.push(allocation);
|
|
76
71
|
}
|
|
72
|
+
this.shrink();
|
|
73
|
+
return results;
|
|
77
74
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
75
|
+
/**
|
|
76
|
+
* Pack a single bin into the sprite.
|
|
77
|
+
*
|
|
78
|
+
* Each bin will have a unique identitifer.
|
|
79
|
+
* If no identifier is supplied in the `id` parameter, one will be created.
|
|
80
|
+
* Note: The supplied `id` is used as an object index, so numeric values are fastest!
|
|
81
|
+
*
|
|
82
|
+
* Bins are automatically refcounted (i.e. a newly packed Bin will have a refcount of 1).
|
|
83
|
+
* When a bin is no longer needed, use the `ShelfPack.unref` function to mark it
|
|
84
|
+
* as unused. When a Bin's refcount decrements to 0, the Bin will be marked
|
|
85
|
+
* as free and its space may be reused by the packing code.
|
|
86
|
+
*
|
|
87
|
+
* @param {number} w Width of the bin to allocate
|
|
88
|
+
* @param {number} h Height of the bin to allocate
|
|
89
|
+
* @param {number|string} [id] Unique identifier for this bin, (if unsupplied, assume it's a new bin and create an id)
|
|
90
|
+
* @returns {Bin} Bin object with `id`, `x`, `y`, `w`, `h` properties, or `null` if allocation failed
|
|
91
|
+
* @example
|
|
92
|
+
* var results = sprite.packOne(12, 16, 'a');
|
|
93
|
+
*/
|
|
94
|
+
packOne(w, h, id) {
|
|
95
|
+
var best = { freebin: -1, shelf: -1, waste: Infinity }, y = 0, bin, shelf, waste, i;
|
|
96
|
+
// if id was supplied, attempt a lookup..
|
|
97
|
+
if (typeof id === 'string' || typeof id === 'number') {
|
|
98
|
+
bin = this.getBin(id);
|
|
99
|
+
if (bin) { // we packed this bin already
|
|
100
|
+
this.ref(bin);
|
|
101
|
+
return bin;
|
|
102
|
+
}
|
|
103
|
+
if (typeof id === 'number') {
|
|
104
|
+
this.maxId = Math.max(id, this.maxId);
|
|
105
|
+
}
|
|
108
106
|
}
|
|
109
|
-
|
|
110
|
-
|
|
107
|
+
else {
|
|
108
|
+
id = ++this.maxId;
|
|
111
109
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
110
|
+
// First try to reuse a free bin..
|
|
111
|
+
for (i = 0; i < this.freebins.length; i++) {
|
|
112
|
+
bin = this.freebins[i];
|
|
113
|
+
// exactly the right height and width, use it..
|
|
114
|
+
if (h === bin.maxh && w === bin.maxw) {
|
|
115
|
+
return this.allocFreebin(i, w, h, id);
|
|
116
|
+
}
|
|
117
|
+
// not enough height or width, skip it..
|
|
118
|
+
if (h > bin.maxh || w > bin.maxw) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
// extra height or width, minimize wasted area..
|
|
122
|
+
if (h <= bin.maxh && w <= bin.maxw) {
|
|
123
|
+
waste = (bin.maxw * bin.maxh) - (w * h);
|
|
124
|
+
if (waste < best.waste) {
|
|
125
|
+
best.waste = waste;
|
|
126
|
+
best.freebin = i;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
126
129
|
}
|
|
127
|
-
//
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
130
|
+
// Next find the best shelf..
|
|
131
|
+
for (i = 0; i < this.shelves.length; i++) {
|
|
132
|
+
shelf = this.shelves[i];
|
|
133
|
+
y += shelf.h;
|
|
134
|
+
// not enough width on this shelf, skip it..
|
|
135
|
+
if (w > shelf.free) {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
// exactly the right height, pack it..
|
|
139
|
+
if (h === shelf.h) {
|
|
140
|
+
return this.allocShelf(i, w, h, id);
|
|
141
|
+
}
|
|
142
|
+
// not enough height, skip it..
|
|
143
|
+
if (h > shelf.h) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
// extra height, minimize wasted area..
|
|
147
|
+
if (h < shelf.h) {
|
|
148
|
+
waste = (shelf.h - h) * w;
|
|
149
|
+
if (waste < best.waste) {
|
|
150
|
+
best.freebin = -1;
|
|
151
|
+
best.waste = waste;
|
|
152
|
+
best.shelf = i;
|
|
153
|
+
}
|
|
133
154
|
}
|
|
134
155
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
for (i = 0; i < this.shelves.length; i++) {
|
|
138
|
-
shelf = this.shelves[i];
|
|
139
|
-
y += shelf.h;
|
|
140
|
-
// not enough width on this shelf, skip it..
|
|
141
|
-
if (w > shelf.free) {
|
|
142
|
-
continue;
|
|
156
|
+
if (best.freebin !== -1) {
|
|
157
|
+
return this.allocFreebin(best.freebin, w, h, id);
|
|
143
158
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
return this.allocShelf(i, w, h, id);
|
|
159
|
+
if (best.shelf !== -1) {
|
|
160
|
+
return this.allocShelf(best.shelf, w, h, id);
|
|
147
161
|
}
|
|
148
|
-
//
|
|
149
|
-
if (h
|
|
150
|
-
|
|
162
|
+
// No free bins or shelves.. add shelf..
|
|
163
|
+
if (h <= (this.h - y) && w <= this.w) {
|
|
164
|
+
shelf = new Shelf(y, this.w, h);
|
|
165
|
+
return this.allocShelf(this.shelves.push(shelf) - 1, w, h, id);
|
|
151
166
|
}
|
|
152
|
-
//
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
167
|
+
// No room for more shelves..
|
|
168
|
+
// If `autoResize` option is set, grow the sprite as follows:
|
|
169
|
+
// * double whichever sprite dimension is smaller (`w1` or `h1`)
|
|
170
|
+
// * if sprite dimensions are equal, grow width before height
|
|
171
|
+
// * accomodate very large bin requests (big `w` or `h`)
|
|
172
|
+
if (this.autoResize) {
|
|
173
|
+
var h1, h2, w1, w2;
|
|
174
|
+
h1 = h2 = this.h;
|
|
175
|
+
w1 = w2 = this.w;
|
|
176
|
+
if (w1 <= h1 || w > w1) { // grow width..
|
|
177
|
+
w2 = Math.max(w, w1) * 2;
|
|
159
178
|
}
|
|
179
|
+
if (h1 < w1 || h > h1) { // grow height..
|
|
180
|
+
h2 = Math.max(h, h1) * 2;
|
|
181
|
+
}
|
|
182
|
+
this.resize(w2, h2);
|
|
183
|
+
return this.packOne(w, h, id); // retry
|
|
160
184
|
}
|
|
185
|
+
return null;
|
|
161
186
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
187
|
+
/**
|
|
188
|
+
* Called by packOne() to allocate a bin by reusing an existing freebin
|
|
189
|
+
*
|
|
190
|
+
* @private
|
|
191
|
+
* @param {number} index Index into the `this.freebins` array
|
|
192
|
+
* @param {number} w Width of the bin to allocate
|
|
193
|
+
* @param {number} h Height of the bin to allocate
|
|
194
|
+
* @param {number|string} id Unique identifier for this bin
|
|
195
|
+
* @returns {Bin} Bin object with `id`, `x`, `y`, `w`, `h` properties
|
|
196
|
+
* @example
|
|
197
|
+
* var bin = sprite.allocFreebin(0, 12, 16, 'a');
|
|
198
|
+
*/
|
|
199
|
+
allocFreebin(index, w, h, id) {
|
|
200
|
+
var bin = this.freebins.splice(index, 1)[0];
|
|
201
|
+
bin.id = id;
|
|
202
|
+
bin.w = w;
|
|
203
|
+
bin.h = h;
|
|
204
|
+
bin.refcount = 0;
|
|
205
|
+
this.bins[id] = bin;
|
|
206
|
+
this.ref(bin);
|
|
207
|
+
return bin;
|
|
167
208
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
209
|
+
/**
|
|
210
|
+
* Called by `packOne() to allocate bin on an existing shelf
|
|
211
|
+
*
|
|
212
|
+
* @private
|
|
213
|
+
* @param {number} index Index into the `this.shelves` array
|
|
214
|
+
* @param {number} w Width of the bin to allocate
|
|
215
|
+
* @param {number} h Height of the bin to allocate
|
|
216
|
+
* @param {number|string} id Unique identifier for this bin
|
|
217
|
+
* @returns {Bin} Bin object with `id`, `x`, `y`, `w`, `h` properties
|
|
218
|
+
* @example
|
|
219
|
+
* var results = sprite.allocShelf(0, 12, 16, 'a');
|
|
220
|
+
*/
|
|
221
|
+
allocShelf(index, w, h, id) {
|
|
222
|
+
var shelf = this.shelves[index];
|
|
223
|
+
var bin = shelf.alloc(w, h, id);
|
|
224
|
+
this.bins[id] = bin;
|
|
225
|
+
this.ref(bin);
|
|
226
|
+
return bin;
|
|
172
227
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
228
|
+
/**
|
|
229
|
+
* Shrink the width/height of the sprite to the bare minimum.
|
|
230
|
+
* Since shelf-pack doubles first width, then height when running out of shelf space
|
|
231
|
+
* this can result in fairly large unused space both in width and height if that happens
|
|
232
|
+
* towards the end of bin packing.
|
|
233
|
+
*/
|
|
234
|
+
shrink() {
|
|
235
|
+
if (this.shelves.length > 0) {
|
|
236
|
+
var w2 = 0;
|
|
237
|
+
var h2 = 0;
|
|
238
|
+
for (var j = 0; j < this.shelves.length; j++) {
|
|
239
|
+
var shelf = this.shelves[j];
|
|
240
|
+
h2 += shelf.h;
|
|
241
|
+
w2 = Math.max(shelf.w - shelf.free, w2);
|
|
242
|
+
}
|
|
243
|
+
this.resize(w2, h2);
|
|
187
244
|
}
|
|
188
|
-
this.resize(w2, h2);
|
|
189
|
-
return this.packOne(w, h, id); // retry
|
|
190
245
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
* @returns {Bin} Bin object with `id`, `x`, `y`, `w`, `h` properties
|
|
202
|
-
* @example
|
|
203
|
-
* var bin = sprite.allocFreebin(0, 12, 16, 'a');
|
|
204
|
-
*/
|
|
205
|
-
ShelfPack.prototype.allocFreebin = function (index, w, h, id) {
|
|
206
|
-
var bin = this.freebins.splice(index, 1)[0];
|
|
207
|
-
bin.id = id;
|
|
208
|
-
bin.w = w;
|
|
209
|
-
bin.h = h;
|
|
210
|
-
bin.refcount = 0;
|
|
211
|
-
this.bins[id] = bin;
|
|
212
|
-
this.ref(bin);
|
|
213
|
-
return bin;
|
|
214
|
-
};
|
|
215
|
-
/**
|
|
216
|
-
* Called by `packOne() to allocate bin on an existing shelf
|
|
217
|
-
*
|
|
218
|
-
* @private
|
|
219
|
-
* @param {number} index Index into the `this.shelves` array
|
|
220
|
-
* @param {number} w Width of the bin to allocate
|
|
221
|
-
* @param {number} h Height of the bin to allocate
|
|
222
|
-
* @param {number|string} id Unique identifier for this bin
|
|
223
|
-
* @returns {Bin} Bin object with `id`, `x`, `y`, `w`, `h` properties
|
|
224
|
-
* @example
|
|
225
|
-
* var results = sprite.allocShelf(0, 12, 16, 'a');
|
|
226
|
-
*/
|
|
227
|
-
ShelfPack.prototype.allocShelf = function (index, w, h, id) {
|
|
228
|
-
var shelf = this.shelves[index];
|
|
229
|
-
var bin = shelf.alloc(w, h, id);
|
|
230
|
-
this.bins[id] = bin;
|
|
231
|
-
this.ref(bin);
|
|
232
|
-
return bin;
|
|
233
|
-
};
|
|
234
|
-
/**
|
|
235
|
-
* Shrink the width/height of the sprite to the bare minimum.
|
|
236
|
-
* Since shelf-pack doubles first width, then height when running out of shelf space
|
|
237
|
-
* this can result in fairly large unused space both in width and height if that happens
|
|
238
|
-
* towards the end of bin packing.
|
|
239
|
-
*/
|
|
240
|
-
ShelfPack.prototype.shrink = function () {
|
|
241
|
-
if (this.shelves.length > 0) {
|
|
242
|
-
var w2 = 0;
|
|
243
|
-
var h2 = 0;
|
|
244
|
-
for (var j = 0; j < this.shelves.length; j++) {
|
|
245
|
-
var shelf = this.shelves[j];
|
|
246
|
-
h2 += shelf.h;
|
|
247
|
-
w2 = Math.max(shelf.w - shelf.free, w2);
|
|
248
|
-
}
|
|
249
|
-
this.resize(w2, h2);
|
|
246
|
+
/**
|
|
247
|
+
* Return a packed bin given its id, or undefined if the id is not found
|
|
248
|
+
*
|
|
249
|
+
* @param {number|string} id Unique identifier for this bin,
|
|
250
|
+
* @returns {Bin} The requested bin, or undefined if not yet packed
|
|
251
|
+
* @example
|
|
252
|
+
* var b = sprite.getBin('a');
|
|
253
|
+
*/
|
|
254
|
+
getBin(id) {
|
|
255
|
+
return this.bins[id];
|
|
250
256
|
}
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
* @param {Bin} bin Bin instance
|
|
267
|
-
* @returns {number} New refcount of the bin
|
|
268
|
-
* @example
|
|
269
|
-
* var bin = sprite.getBin('a');
|
|
270
|
-
* sprite.ref(bin);
|
|
271
|
-
*/
|
|
272
|
-
ShelfPack.prototype.ref = function (bin) {
|
|
273
|
-
if (++bin.refcount === 1) { // a new Bin.. record height in stats historgram..
|
|
274
|
-
var h = bin.h;
|
|
275
|
-
this.stats[h] = (this.stats[h] | 0) + 1;
|
|
257
|
+
/**
|
|
258
|
+
* Increment the ref count of a bin and update statistics.
|
|
259
|
+
*
|
|
260
|
+
* @param {Bin} bin Bin instance
|
|
261
|
+
* @returns {number} New refcount of the bin
|
|
262
|
+
* @example
|
|
263
|
+
* var bin = sprite.getBin('a');
|
|
264
|
+
* sprite.ref(bin);
|
|
265
|
+
*/
|
|
266
|
+
ref(bin) {
|
|
267
|
+
if (++bin.refcount === 1) { // a new Bin.. record height in stats historgram..
|
|
268
|
+
var h = bin.h;
|
|
269
|
+
this.stats[h] = (this.stats[h] | 0) + 1;
|
|
270
|
+
}
|
|
271
|
+
return bin.refcount;
|
|
276
272
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
273
|
+
/**
|
|
274
|
+
* Decrement the ref count of a bin and update statistics.
|
|
275
|
+
* The bin will be automatically marked as free space once the refcount reaches 0.
|
|
276
|
+
*
|
|
277
|
+
* @param {Bin} bin Bin instance
|
|
278
|
+
* @returns {number} New refcount of the bin
|
|
279
|
+
* @example
|
|
280
|
+
* var bin = sprite.getBin('a');
|
|
281
|
+
* sprite.unref(bin);
|
|
282
|
+
*/
|
|
283
|
+
unref(bin) {
|
|
284
|
+
if (bin.refcount === 0) {
|
|
285
|
+
return 0;
|
|
286
|
+
}
|
|
287
|
+
if (--bin.refcount === 0) {
|
|
288
|
+
this.stats[bin.h]--;
|
|
289
|
+
delete this.bins[bin.id];
|
|
290
|
+
this.freebins.push(bin);
|
|
291
|
+
}
|
|
292
|
+
return bin.refcount;
|
|
292
293
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
294
|
+
/**
|
|
295
|
+
* Clear the sprite. Resets everything and resets statistics.
|
|
296
|
+
*
|
|
297
|
+
* @example
|
|
298
|
+
* sprite.clear();
|
|
299
|
+
*/
|
|
300
|
+
clear() {
|
|
301
|
+
this.shelves = [];
|
|
302
|
+
this.freebins = [];
|
|
303
|
+
this.stats = {};
|
|
304
|
+
this.bins = {};
|
|
305
|
+
this.maxId = 0;
|
|
297
306
|
}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
* Resize the sprite.
|
|
315
|
-
*
|
|
316
|
-
* @param {number} w Requested new sprite width
|
|
317
|
-
* @param {number} h Requested new sprite height
|
|
318
|
-
* @returns {boolean} `true` if resize succeeded, `false` if failed
|
|
319
|
-
* @example
|
|
320
|
-
* sprite.resize(256, 256);
|
|
321
|
-
*/
|
|
322
|
-
ShelfPack.prototype.resize = function (w, h) {
|
|
323
|
-
this.w = w;
|
|
324
|
-
this.h = h;
|
|
325
|
-
for (var i = 0; i < this.shelves.length; i++) {
|
|
326
|
-
this.shelves[i].resize(w);
|
|
307
|
+
/**
|
|
308
|
+
* Resize the sprite.
|
|
309
|
+
*
|
|
310
|
+
* @param {number} w Requested new sprite width
|
|
311
|
+
* @param {number} h Requested new sprite height
|
|
312
|
+
* @returns {boolean} `true` if resize succeeded, `false` if failed
|
|
313
|
+
* @example
|
|
314
|
+
* sprite.resize(256, 256);
|
|
315
|
+
*/
|
|
316
|
+
resize(w, h) {
|
|
317
|
+
this.w = w;
|
|
318
|
+
this.h = h;
|
|
319
|
+
for (var i = 0; i < this.shelves.length; i++) {
|
|
320
|
+
this.shelves[i].resize(w);
|
|
321
|
+
}
|
|
322
|
+
return true;
|
|
327
323
|
}
|
|
328
|
-
|
|
329
|
-
};
|
|
324
|
+
}
|
|
330
325
|
/**
|
|
331
326
|
* Create a new Shelf.
|
|
332
327
|
*
|
|
333
328
|
* @private
|
|
334
|
-
* @class Shelf
|
|
335
|
-
* @param {number} y Top coordinate of the new shelf
|
|
336
|
-
* @param {number} w Width of the new shelf
|
|
337
|
-
* @param {number} h Height of the new shelf
|
|
338
329
|
* @example
|
|
339
330
|
* var shelf = new Shelf(64, 512, 24);
|
|
340
331
|
*/
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
* @param {number} h Height of the bin to allocate
|
|
353
|
-
* @param {number|string} id Unique id of the bin to allocate
|
|
354
|
-
* @returns {Bin} Bin object with `id`, `x`, `y`, `w`, `h` properties, or `null` if allocation failed
|
|
355
|
-
* @example
|
|
356
|
-
* shelf.alloc(12, 16, 'a');
|
|
357
|
-
*/
|
|
358
|
-
Shelf.prototype.alloc = function (w, h, id) {
|
|
359
|
-
if (w > this.free || h > this.h) {
|
|
360
|
-
return null;
|
|
332
|
+
class Shelf {
|
|
333
|
+
/**
|
|
334
|
+
* @param {number} y Top coordinate of the new shelf
|
|
335
|
+
* @param {number} w Width of the new shelf
|
|
336
|
+
* @param {number} h Height of the new shelf
|
|
337
|
+
*/
|
|
338
|
+
constructor(y, w, h) {
|
|
339
|
+
this.x = 0;
|
|
340
|
+
this.y = y;
|
|
341
|
+
this.w = this.free = w;
|
|
342
|
+
this.h = h;
|
|
361
343
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
344
|
+
/**
|
|
345
|
+
* Allocate a single bin into the shelf.
|
|
346
|
+
*
|
|
347
|
+
* @private
|
|
348
|
+
* @param {number} w Width of the bin to allocate
|
|
349
|
+
* @param {number} h Height of the bin to allocate
|
|
350
|
+
* @param {number|string} id Unique id of the bin to allocate
|
|
351
|
+
* @returns {Bin} Bin object with `id`, `x`, `y`, `w`, `h` properties, or `null` if allocation failed
|
|
352
|
+
* @example
|
|
353
|
+
* shelf.alloc(12, 16, 'a');
|
|
354
|
+
*/
|
|
355
|
+
alloc(w, h, id) {
|
|
356
|
+
if (w > this.free || h > this.h) {
|
|
357
|
+
return null;
|
|
358
|
+
}
|
|
359
|
+
var x = this.x;
|
|
360
|
+
this.x += w;
|
|
361
|
+
this.free -= w;
|
|
362
|
+
return new Bin(id, x, this.y, w, h, w, this.h);
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Resize the shelf.
|
|
366
|
+
*
|
|
367
|
+
* @private
|
|
368
|
+
* @param {number} w Requested new width of the shelf
|
|
369
|
+
* @returns {boolean} true
|
|
370
|
+
* @example
|
|
371
|
+
* shelf.resize(512);
|
|
372
|
+
*/
|
|
373
|
+
resize(w) {
|
|
374
|
+
this.free += (w - this.w);
|
|
375
|
+
this.w = w;
|
|
376
|
+
return true;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
381
379
|
/**
|
|
382
380
|
* Create a new Bin object.
|
|
383
381
|
*
|
|
384
|
-
* @class Bin
|
|
385
|
-
* @param {number|string} id Unique id of the bin
|
|
386
|
-
* @param {number} x Left coordinate of the bin
|
|
387
|
-
* @param {number} y Top coordinate of the bin
|
|
388
|
-
* @param {number} w Width of the bin
|
|
389
|
-
* @param {number} h Height of the bin
|
|
390
|
-
* @param {number} [maxw] Max width of the bin (defaults to `w` if not provided)
|
|
391
|
-
* @param {number} [maxh] Max height of the bin (defaults to `h` if not provided)
|
|
392
382
|
* @example
|
|
393
383
|
* var bin = new Bin('a', 0, 0, 12, 16);
|
|
394
384
|
*/
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
385
|
+
export class Bin {
|
|
386
|
+
/**
|
|
387
|
+
* @param {number|string} id Unique id of the bin
|
|
388
|
+
* @param {number} x Left coordinate of the bin
|
|
389
|
+
* @param {number} y Top coordinate of the bin
|
|
390
|
+
* @param {number} w Width of the bin
|
|
391
|
+
* @param {number} h Height of the bin
|
|
392
|
+
* @param {number} [maxw] Max width of the bin (defaults to `w` if not provided)
|
|
393
|
+
* @param {number} [maxh] Max height of the bin (defaults to `h` if not provided)
|
|
394
|
+
*/
|
|
395
|
+
constructor(id, x, y, w, h, maxw, maxh) {
|
|
396
|
+
this.id = id;
|
|
397
|
+
this.x = x;
|
|
398
|
+
this.y = y;
|
|
399
|
+
this.w = w;
|
|
400
|
+
this.h = h;
|
|
401
|
+
this.maxw = maxw || w;
|
|
402
|
+
this.maxh = maxh || h;
|
|
403
|
+
this.refcount = 0;
|
|
404
|
+
}
|
|
404
405
|
}
|
|
405
406
|
//# sourceMappingURL=index.js.map
|