{"_id":"@cennavi-fe/shelf-pack","_rev":"2-25b60c7d12cc76a956c3625180c81a96","name":"@cennavi-fe/shelf-pack","dist-tags":{"latest":"3.2.0"},"versions":{"3.2.0":{"name":"@cennavi-fe/shelf-pack","version":"3.2.0","keywords":["bin packing","sprite"],"author":{"name":"Bryan Housel","email":"bryan@mapbox.com"},"license":"ISC","_id":"@cennavi-fe/shelf-pack@3.2.0","maintainers":[{"name":"wuhaoyuan","email":"alan_why@foxmail.com"},{"name":"zhoumingrui","email":"441821595@qq.com"},{"name":"hhui90068","email":"15738779822@163.com"},{"name":"wb9527","email":"1129305053@qq.com"},{"name":"ndwgg","email":"ndwgg@qq.com"}],"homepage":"https://github.com/mapbox/shelf-pack#readme","bugs":{"url":"https://github.com/mapbox/shelf-pack/issues"},"dist":{"shasum":"5ff7c21122db7b2b7e4433c902ecb4c6259f5552","tarball":"https://registry.npmjs.org/@cennavi-fe/shelf-pack/-/shelf-pack-3.2.0.tgz","fileCount":12,"integrity":"sha512-3VIdvBHHezk+6nuqBT7g5iBZHI61fPHC4e/YripdgKB0KdNu/4YiLQ5kw1ZHIe2otAgVxikf3CZw5Kalcxxiow==","signatures":[{"sig":"MEQCIFZbRbYawmIRal97HJPOgs7Oza4QZn5Yt117+d0nFUg4AiB3FbFkwnX7lL4HerKAr0B+ZsYPUeHqVqZ5iHGLOE7ttQ==","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":43248},"main":"index.js","module":"index.mjs","engines":{"node":">=6.0.0"},"gitHead":"a79242aa2025ab803a159f2268322f41cf179f7d","scripts":{"docs":"documentation build index.mjs --lint --github --format html --output docs/","lint":"eslint index.mjs test/ bench/","test":"npm run build && npm run lint && tap --cov test/*.js","bench":"npm run build && node bench/bench.js","build":"rollup -f umd -n ShelfPack index.mjs --no-indent --no-strict -o index.js"},"_npmUser":{"name":"zhoumingrui","email":"441821595@qq.com"},"deprecated":false,"repository":{"url":"git+https://github.com/mapbox/shelf-pack.git","type":"git"},"_npmVersion":"6.14.17","description":"A 2D rectangular bin packing data structure that uses the Shelf Best Height Fit heuristic","directories":{},"_nodeVersion":"14.20.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tap":"^12.0.0","eslint":"^5.0.0","rollup":"0.60.0","bin-pack":"1.0.2","benchmark":"^2.1.0","coveralls":"^3.0.0","documentation":"4.0.0-beta5"},"_npmOperationalInternal":{"tmp":"tmp/shelf-pack_3.2.0_1688608643542_0.5526725512302777","host":"s3://npm-registry-packages"}}},"time":{"created":"2023-07-06T01:57:23.489Z","modified":"2025-08-20T06:57:47.735Z","3.2.0":"2023-07-06T01:57:23.723Z"},"bugs":{"url":"https://github.com/mapbox/shelf-pack/issues"},"author":{"name":"Bryan Housel","email":"bryan@mapbox.com"},"license":"ISC","homepage":"https://github.com/mapbox/shelf-pack#readme","keywords":["bin packing","sprite"],"repository":{"url":"git+https://github.com/mapbox/shelf-pack.git","type":"git"},"description":"A 2D rectangular bin packing data structure that uses the Shelf Best Height Fit heuristic","maintainers":[{"email":"ndwgg@qq.com","name":"ndwgg"},{"email":"1129305053@qq.com","name":"wb9527"},{"email":"441821595@qq.com","name":"zhoumingrui"},{"email":"alan_why@foxmail.com","name":"wuhaoyuan"}],"readme":"[![npm version](https://badge.fury.io/js/%40mapbox%2Fshelf-pack.svg)](https://badge.fury.io/js/%40mapbox%2Fshelf-pack)\r\n[![Build Status](https://secure.travis-ci.org/mapbox/shelf-pack.svg)](http://travis-ci.org/mapbox/shelf-pack)\r\n[![Coverage Status](https://coveralls.io/repos/github/mapbox/shelf-pack/badge.svg?branch=master)](https://coveralls.io/github/mapbox/shelf-pack?branch=master)\r\n\r\n## shelf-pack\r\n\r\nA 2D rectangular [bin packing](https://en.wikipedia.org/wiki/Bin_packing_problem)\r\ndata structure that uses the Shelf Best Height Fit heuristic.\r\n\r\n\r\n### What is it?\r\n\r\n`shelf-pack` is a library for packing little rectangles into a big rectangle.  This sounds simple enough,\r\nbut finding an optimal packing is a problem with [NP-Complete](https://en.wikipedia.org/wiki/NP-completeness)\r\ncomplexity.  One useful application of bin packing is to assemble icons or glyphs into a sprite texture.\r\n\r\nThere are many ways to approach the bin packing problem, but `shelf-pack` uses the Shelf Best\r\nHeight Fit heuristic.  It works by dividing the total space into \"shelves\", each with a certain height.\r\nThe allocator packs rectangles onto whichever shelf minimizes the amount of wasted vertical space.\r\n\r\n`shelf-pack` is simple, fast, and works best when the rectangles have similar heights (icons and glyphs\r\nare like this).  It is not a generalized bin packer, and can potentially waste a lot of space if the\r\nrectangles vary significantly in height.\r\n\r\n\r\n### How fast is it?\r\n\r\nReally fast!  `shelf-pack` is several orders of magnitude faster than the more general\r\n[`bin-pack`](https://www.npmjs.com/package/bin-pack) library.\r\n\r\n```bash\r\n> npm run bench\r\n\r\nShelfPack single allocate fixed size bins x 1,610 ops/sec ±1.21% (90 runs sampled)\r\nShelfPack single allocate random width bins x 1,475 ops/sec ±1.00% (89 runs sampled)\r\nShelfPack single allocate random height bins x 1,458 ops/sec ±1.00% (90 runs sampled)\r\nShelfPack single allocate random height and width bins x 1,346 ops/sec ±0.96% (89 runs sampled)\r\nShelfPack batch allocate fixed size bins x 1,522 ops/sec ±1.06% (86 runs sampled)\r\nShelfPack batch allocate random width bins x 1,427 ops/sec ±1.06% (89 runs sampled)\r\nShelfPack batch allocate random height bins x 1,350 ops/sec ±1.63% (90 runs sampled)\r\nShelfPack batch allocate random height and width bins x 1,257 ops/sec ±1.02% (89 runs sampled)\r\nBinPack batch allocate fixed size bins x 2.21 ops/sec ±6.60% (10 runs sampled)\r\nBinPack batch allocate random width bins x 0.50 ops/sec ±2.25% (6 runs sampled)\r\nBinPack batch allocate random height bins x 0.51 ops/sec ±1.97% (6 runs sampled)\r\nBinPack batch allocate random height and width bins x 0.51 ops/sec ±1.37% (6 runs sampled)\r\n```\r\n\r\n\r\n### Usage\r\n\r\n#### Basic Usage\r\n\r\n```js\r\nvar ShelfPack = require('@mapbox/shelf-pack');\r\n\r\n// Initialize the sprite with a width and height..\r\nvar sprite = new ShelfPack(64, 64);\r\n\r\n// Pack bins one at a time..\r\nfor (var i = 0; i < 5; i++) {\r\n    // packOne() accepts parameters: `width`, `height`, `id`\r\n    // and returns a single allocated Bin object..\r\n    // `id` is optional - if you skip it, shelf-pack will make up a number for you..\r\n    // (Protip: numeric ids are much faster than string ids)\r\n\r\n    var bin = sprite.packOne(32, 32);\r\n    console.log(bin || 'out of space');\r\n}\r\n\r\n/* output:\r\nBin { id: 1, x: 0, y: 0, w: 32, h: 32, maxw: 32, maxh: 32, refcount: 1 }\r\nBin { id: 2, x: 32, y: 0, w: 32, h: 32, maxw: 32, maxh: 32, refcount: 1 }\r\nBin { id: 3, x: 0, y: 32, w: 32, h: 32, maxw: 32, maxh: 32, refcount: 1 }\r\nBin { id: 4, x: 32, y: 32, w: 32, h: 32, maxw: 32, maxh: 32, refcount: 1 }\r\nout of space\r\n*/\r\n\r\n// Clear sprite and start over..\r\nsprite.clear();\r\n\r\n// Or, resize sprite by passing larger dimensions..\r\nsprite.resize(128, 128);   // width, height\r\n\r\n```\r\n\r\n\r\n#### Batch packing\r\n\r\n```js\r\nvar ShelfPack = require('@mapbox/shelf-pack');\r\n\r\n// If you don't want to think about the size of the sprite,\r\n// the `autoResize` option will allow it to grow as needed..\r\nvar sprite = new ShelfPack(10, 10, { autoResize: true });\r\n\r\n// Bins can be allocated in batches..\r\n// Each requested bin should have `w`, `h` (or `width`, `height`) properties..\r\nvar requests = [\r\n    { id: 'a', width: 10, height: 10 },\r\n    { id: 'b', width: 10, height: 12 },\r\n    { id: 'c', w: 10, h: 12 },\r\n    { id: 'd', w: 10, h: 10 }\r\n];\r\n\r\n// pack() returns an Array of packed Bin objects..\r\nvar results = sprite.pack(requests);\r\n\r\nresults.forEach(function(bin) {\r\n    console.log(bin);\r\n});\r\n\r\n/* output:\r\nBin { id: 'a', x: 0, y: 0, w: 10, h: 10, maxw: 10, maxh: 10, refcount: 1 }\r\nBin { id: 'b', x: 0, y: 10, w: 10, h: 12, maxw: 10, maxh: 12, refcount: 1 }\r\nBin { id: 'c', x: 10, y: 10, w: 10, h: 12, maxw: 10, maxh: 12, refcount: 1 }\r\nBin { id: 'd', x: 10, y: 0, w: 10, h: 10, maxw: 10, maxh: 10, refcount: 1 }\r\n*/\r\n\r\n// If you don't mind letting ShelfPack modify your objects,\r\n// the `inPlace` option will decorate your bin objects with `x` and `y` properties.\r\n// Fancy!\r\nvar myBins = [\r\n    { id: 'e', width: 12, height: 24 },\r\n    { id: 'f', width: 12, height: 12 },\r\n    { id: 'g', w: 10, h: 10 }\r\n];\r\n\r\nsprite.pack(myBins, { inPlace: true });\r\nmyBins.forEach(function(bin) {\r\n    console.log(bin);\r\n});\r\n\r\n/* output:\r\n{ id: 'e', width: 12, height: 24, x: 0, y: 22 }\r\n{ id: 'f', width: 12, height: 12, x: 20, y: 10 }\r\n{ id: 'g', w: 10, h: 10, x: 20, y: 0 }\r\n*/\r\n\r\n```\r\n\r\n#### Reference Counting\r\n\r\n```js\r\nvar ShelfPack = require('@mapbox/shelf-pack');\r\n\r\n// Initialize the sprite with a width and height..\r\nvar sprite = new ShelfPack(64, 64);\r\n\r\n// Allocated bins are automatically reference counted.\r\n// They start out having a refcount of 1.\r\n[100, 101, 102].forEach(function(id) {\r\n    var bin = sprite.packOne(16, 16, id);\r\n    console.log(bin);\r\n});\r\n\r\n/* output:\r\nBin { id: 100, x: 0, y: 0, w: 16, h: 16, maxw: 16, maxh: 16, refcount: 1 }\r\nBin { id: 101, x: 16, y: 0, w: 16, h: 16, maxw: 16, maxh: 16, refcount: 1 }\r\nBin { id: 102, x: 32, y: 0, w: 16, h: 16, maxw: 16, maxh: 16, refcount: 1 }\r\n*/\r\n\r\n// If you try to pack the same id again, shelf-pack will not re-pack it.\r\n// Instead, it will increment the reference count automatically..\r\nvar bin102 = sprite.packOne(16, 16, 102);\r\nconsole.log(bin102);\r\n\r\n/* output:\r\nBin { id: 102, x: 32, y: 0, w: 16, h: 16, maxw: 16, maxh: 16, refcount: 2 }\r\n*/\r\n\r\n// You can also manually increment the reference count..\r\nvar bin101 = sprite.getBin(101);\r\nsprite.ref(bin101);\r\nconsole.log(bin101);\r\n\r\n/* output:\r\nBin { id: 101, x: 16, y: 0, w: 16, h: 16, maxw: 16, maxh: 16, refcount: 2 }\r\n*/\r\n\r\n// ...and decrement it!\r\nvar bin100 = sprite.getBin(100);\r\nsprite.unref(bin100);\r\nconsole.log(bin100);\r\n\r\n/* output:\r\nBin { id: 100, x: 0, y: 0, w: 16, h: 16, maxw: 16, maxh: 16, refcount: 0 }\r\n*/\r\n\r\n// Bins with a refcount of 0 are considered free space.\r\n// Next time a bin is packed, shelf-back tries to reuse free space first.\r\n// See how Bin 103 gets allocated at [0,0] - Bin 100's old spot!\r\nvar bin103 = sprite.packOne(16, 15, 103);\r\nconsole.log(bin103);\r\n\r\n/* output:\r\nBin { id: 103, x: 0, y: 0, w: 16, h: 15, maxw: 16, maxh: 16, refcount: 1 }\r\n*/\r\n\r\n// Bin 103 may be smaller (16x15) but it knows 16x16 was its original size.\r\n// If that space becomes free again, a 16x16 bin will still fit there.\r\nsprite.unref(bin103)\r\nvar bin104 = sprite.packOne(16, 16, 104);\r\nconsole.log(bin104);\r\n\r\n/* output:\r\nBin { id: 104, x: 0, y: 0, w: 16, h: 16, maxw: 16, maxh: 16, refcount: 1 }\r\n*/\r\n\r\n```\r\n\r\n\r\n### Documentation\r\n\r\nComplete API documentation is here:  http://mapbox.github.io/shelf-pack/\r\n\r\n\r\n### See also\r\n\r\nJ. Jylänky, \"A Thousand Ways to Pack the Bin - A Practical\r\nApproach to Two-Dimensional Rectangle Bin Packing,\"\r\nhttp://clb.demon.fi/files/RectangleBinPack.pdf, 2010\r\n","readmeFilename":"README.md"}