| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 | /** * potpack - by [@mourner](https://github.com/mourner) *  * A tiny JavaScript function for packing 2D rectangles into a near-square container,  * which is useful for generating CSS sprites and WebGL textures. Similar to  * [shelf-pack](https://github.com/mapbox/shelf-pack), but static (you can't add items  * once a layout is generated), and aims for maximal space utilization. * * A variation of algorithms used in [rectpack2D](https://github.com/TeamHypersomnia/rectpack2D) * and [bin-pack](https://github.com/bryanburgers/bin-pack), which are in turn based  * on [this article by Blackpawn](http://blackpawn.com/texts/lightmaps/default.html). *  * @license * ISC License *  * Copyright (c) 2018, Mapbox *  * Permission to use, copy, modify, and/or distribute this software for any purpose * with or without fee is hereby granted, provided that the above copyright notice * and this permission notice appear in all copies. *  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF * THIS SOFTWARE. */function potpack(boxes) {	// calculate total box area and maximum box width	let area = 0;	let maxWidth = 0;		for (const box of boxes) {		area += box.w * box.h;		maxWidth = Math.max(maxWidth, box.w);	}		// sort the boxes for insertion by height, descending	boxes.sort((a, b) => b.h - a.h);		// aim for a squarish resulting container,	// slightly adjusted for sub-100% space utilization	const startWidth = Math.max(Math.ceil(Math.sqrt(area / 0.95)), maxWidth);		// start with a single empty space, unbounded at the bottom	const spaces = [{x: 0, y: 0, w: startWidth, h: Infinity}];		let width = 0;	let height = 0;		for (const box of boxes) {		// look through spaces backwards so that we check smaller spaces first		for (let i = spaces.length - 1; i >= 0; i--) {			const space = spaces[i];						// look for empty spaces that can accommodate the current box			if (box.w > space.w || box.h > space.h) continue;						// found the space; add the box to its top-left corner			// |-------|-------|			// |  box  |       |			// |_______|       |			// |         space |			// |_______________|			box.x = space.x;			box.y = space.y;						height = Math.max(height, box.y + box.h);			width = Math.max(width, box.x + box.w);						if (box.w === space.w && box.h === space.h) {				// space matches the box exactly; remove it				const last = spaces.pop();				if (i < spaces.length) spaces[i] = last;						} else if (box.h === space.h) {				// space matches the box height; update it accordingly				// |-------|---------------|				// |  box  | updated space |				// |_______|_______________|				space.x += box.w;				space.w -= box.w;						} else if (box.w === space.w) {				// space matches the box width; update it accordingly				// |---------------|				// |      box      |				// |_______________|				// | updated space |				// |_______________|				space.y += box.h;				space.h -= box.h;						} else {				// otherwise the box splits the space into two spaces				// |-------|-----------|				// |  box  | new space |				// |_______|___________|				// | updated space     |				// |___________________|				spaces.push({					x: space.x + box.w,					y: space.y,					w: space.w - box.w,					h: box.h				});				space.y += box.h;				space.h -= box.h;			}			break;		}	}		return {		w: width, // container width		h: height, // container height		fill: (area / (width * height)) || 0 // space utilization	};}export { potpack };
 |