PHPackages                             aslamhus/rectpacker - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. aslamhus/rectpacker

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

aslamhus/rectpacker
===================

heuristic algorithm for efficiently packing rectangles of a fixed aspect ratio into a defined space, addressing the NP-hard bin packing problem through iterative adjustment of tile sizes and arrangement.

v3.0.1(2y ago)012MITJavaScript

Since Feb 10Pushed 2y ago1 watchersCompare

[ Source](https://github.com/aslamhus/RectanglePacker)[ Packagist](https://packagist.org/packages/aslamhus/rectpacker)[ RSS](/packages/aslamhus-rectpacker/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (1)Versions (7)Used By (0)

Rectangle Packer
================

[](#rectangle-packer)

`RectanglePacker` is a JavaScript\\PHP class designed to efficiently pack rectangles of the same aspect ratio into a defined space, tackling the NP-hard bin packing problem using a heuristic algorithm. For more information on this problem see the [wiki](https://en.wikipedia.org/wiki/Rectangle_packing). This heuristic solves the second variant listed in the article, ***Packing identical squares in a rectilinear polygon.***

Defining the problem
--------------------

[](#defining-the-problem)

I designed this algorithm in order to maximally **fill** the horizontal and vertical space within different screen areas with a grid of tiles where only the aspect ratio was known and the number of videos was variable. In my use case, the aspect ratio was 4/5.

[![a visual description of the problem](/rectangle-packer-problem.jpg)](/rectangle-packer-problem.jpg)

### CSS Layout Algorithms

[](#css-layout-algorithms)

I couldn't achieve the desired effect with browser layout algorithms like css `flexbox` or `grid`. Neither could maximally fill containers both horizontally and vertically without either explicitly setting a height/width value for a flex/grid-item or using javascript to correct the layout (though I would love to see someone prove me wrong!). Regardless, I needed an implementation that could work on the server, not the client side.

### Try the algorithm visualizer online

[](#try-the-algorithm-visualizer-online)

If you'd like to take the algorithm for a spin, you can find a testing application online which visualizes the packer at work:

Play with different screen areas, numbers of tiles, gutter size, tile aspect ratio and more.

[![rectangle packing algorithm visualizer](/visualizer.png)](/visualizer.png)

Usage
-----

[](#usage)

This class is available in `JavaScript` and `PHP` for client and server implementation.

### JavaScript

[](#javascript)

Clone the repo and import from the src directory. If requested, I'll make this available as an npm package.

#### Clone the repo

[](#clone-the-repo)

```
git clone https://github.com/aslamhus/RectanglePacker.git
```

#### Import and use

[](#import-and-use)

```
import RectanglePacker from '../RectanglePacker/src/RectanglePacker.js';

const packer = new RectanglePacker({
  screenArea: [480, 480],
  tiles: [1, 2, 3, 4, 5],
  tileAspectRatio: 4 / 5,
});
const result = packer.pack();
```

### PHP

[](#php)

#### install with composer

[](#install-with-composer)

```
composer require aslamhus/rectpacker
```

### Use

[](#use)

```
$rectPacker = new Aslamhus\RectPacker\RectPacker([
  'screenArea' => [480,480],
  'tiles' => [1,2,3,4,5],
  'tileAspectRatio' => 4/5
])
$result = $rectPacker->pack();
```

### Result

[](#result)

The heuristic outputs the (x,y) `positions` for each tile of the grid, allowing you to arrange your grid based on the coordinates therein. The result of the heuristic, if successful, will be an object (or in the PHP class an associative array) with the following keys:

```
const {
  tileWidth : 0, // the width of each tile (excluding gutter)
  tileHeight: 0, // the height of each tile (excluding the gutter)
  columns: 0, // the grid columns
  rows: 0, // the grid rows
  realWidth: 0 // the width of the grid (including gutter)
   realHeight: 0, // the height of the grid  (including gutter)
  positions: [], // an array of positions corresponding to the tiles array you gave in the constructor. Each tile has an (x,y) coordinate according to its position in the grid
  tiles: [], // the original tiles array you supplied in the constructor
  tries : [], // an array with data for each iteration of the packer providing granular analysis of the heuristic
} = result;
```

If unsuccessful, `RectanglePacker` will throw an error.

Options
-------

[](#options)

The `RectanglePacker` algorithm's behaviour can be configured with the following options which can be set when initializing an instance of the `RectanglePacker` or when calling the `setOptions` method to reinitialize the algorithm. Below is a detailed description of each configurable option:

Required parameters
-------------------

[](#required-parameters)

### `screenArea`

[](#screenarea)

- **Description:** Specifies the dimensions of the screen area where rectangles need to be packed.
- **Type:** Array of two numbers representing width and height.

### `tiles`

[](#tiles)

- **Description:** An array of strings representing the source of each tile.
- **Type:** Array of strings.

### `tileAspectRatio`

[](#tileaspectratio)

- **Description:** The fixed aspect ratio of the tiles.
- **Type:** Number.

Constraints (Optional)
----------------------

[](#constraints-optional)

### `gutter`

[](#gutter)

- **Description:** The spacing between tiles.
- **Type:** Number.
- **Default Value:** 0.

### `minTileWidth`

[](#mintilewidth)

- **Description:** The minimum width of each tile.
- **Type:** Number.
- **Default Value:** 0.

### `minTileHeight`

[](#mintileheight)

- **Description:** The minimum height of each tile.
- **Type:** Number.
- **Default Value:** 0.

### `maxTileHeight`

[](#maxtileheight)

- **Description:** The maximum height of each tile.
- **Type:** Number.
- **Default Value:** 0.

### `columns`

[](#columns)

- **Description:** The fixed number of columns. If set, the best guess for tile height will be calculated based on the columns.
- **Type:** Number.
- **Default Value:** 0.

### `allowIncompleteRow`

[](#allowincompleterow)

- **Description:** If set to true, the heuristic will allow an incomplete row when there are less tiles available than specified by the columns constraint. For instance, if you have specified that the tiles should be arranged to fit the screen area with 8 columns, but you only have 3 tiles, `allowIncompleteRow` will arrange the tiles horizontally as if there were enough tiles to obey the columns constraint. Without `allowIncompleteRow` the algorith would throw the `Could not satisfy columns constraint` or `Underflow Screen Width` error/exception.
- **Type:** Boolean.
- **Default Value:** false.

### `completeRectangle`

[](#completerectangle)

- **Description:** If set to true, the heuristic will try to make the rectangle complete, i.e., all rows will be full.
- **Type:** Boolean.
- **Default Value:** false.

### `canRemoveTiles`

[](#canremovetiles)

- **Description:** If set to true, tiles will be removed if the solution is not possible.
- **Type:** Boolean.
- **Default Value:** false.

### `tryLimit`

[](#trylimit)

- **Description:** The maximum number of tries before the heuristic gives up.
- **Type:** Number.
- **Default Value:** 800.

### `errorMargin`

[](#errormargin)

- **Description:** The error margin for tile dimensions.
- **Type:** Number.
- **Default Value:** 0.01.

### `performanceLimit`

[](#performancelimit)

- **Description:** The limit for performance in milliseconds.
- **Type:** Number.
- **Default Value:** 1000.

### `debug`

[](#debug)

- **Description:** If set to true, debug information will be logged to the console.
- **Type:** Boolean.
- **Default Value:** false.

Callback Option
---------------

[](#callback-option)

### `onError`

[](#onerror)

- **Description:** Callback function to handle errors. It receives an error message as a parameter.
- **Type:** Function.
- **Default Value:** null.

### Example

[](#example)

```
const options = {
  screenArea: [800, 600],
  tiles: ['tile1.jpg', 'tile2.jpg', 'tile3.jpg'],
  tileAspectRatio: 0.75,
  gutter: 5,
  columns: 0, // 0 means no fixed columns
  allowIncompleteRow: false,
  completeRectangle: false,
  canRemoveTiles: false,
  tryLimit: 800,
  errorMargin: 0.01,
  performanceLimit: 1000,
  debug: false,
  onError: (error) => console.error(error),
};

const packer = new RectanglePacker(options);
const result = packer.pack();
console.log(result);
```

Efficiency
----------

[](#efficiency)

Though I have not extensively measured the time complexity of the algorithm, most cases are solved within 1-4 milliseconds and 1 - 10 iterations. As you add more constraints, the time complexity will increase. When I have time (haha!) I would love to measure this more precisely. Feedback/observations are welcome!

Potential Improvements
----------------------

[](#potential-improvements)

### Metaheuristic

[](#metaheuristic)

Run the heuristic multiple times with different starting best guesses, potentially leveraging web workers for efficiency if necessary. Develop a method to measure the viability of the solutions, with remaining space as the main criterion.

Unit Testing
------------

[](#unit-testing)

`RectanglePacker` repo includes a `json` file with an array of test values, each with expected outputs. You can test both the `PHP` and `JavaScript` implentations of the algorithm with these test values.

### PHPUnit tests

[](#phpunit-tests)

```
composer run test-rect-packer
```

### JavaScript tests

[](#javascript-tests)

```
npm run test
```

### Note on gutter accuracy \\ Browser sub-pixel rounding

[](#note-on-gutter-accuracy--browser-sub-pixel-rounding)

In the testing application the gutter may appear off by a pixel or two. This is because the browser rounds pixel values. If the gutter is small and each tile width is rounded up or down (depending on your browser), the gutter at the end of each row will appear truncated. This is a known issue and not a bug in the algorithm. You can examine the tile positions in the result of the packer to confirm that the gutter values are correct. At a later date, I will attempt to account for this pixel rounding issue in the JavaScript implementation of the algorithm.

License
-------

[](#license)

This Rectangle Packer class is licensed under the [MIT License](LICENSE). Feel free to use and modify it according to your needs.

### Happy Packing!!

[](#happy-packing)

###  Health Score

21

—

LowBetter than 19% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity5

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity46

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~2 days

Total

6

Last Release

814d ago

Major Versions

v2.2.0 → v3.0.02024-02-22

### Community

Maintainers

![](https://www.gravatar.com/avatar/cf398f3954c2155216c23f9573a1729d46cbe95f9fdf17fc3da7d0da55fe1903?d=identicon)[aslamhus](/maintainers/aslamhus)

---

Top Contributors

[![aslamhus](https://avatars.githubusercontent.com/u/76789892?v=4)](https://github.com/aslamhus "aslamhus (37 commits)")

---

Tags

bin-packingjs-rectangle-packerphp-rectange-packerrectangle-packerrectangle-packing

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/aslamhus-rectpacker/health.svg)

```
[![Health](https://phpackages.com/badges/aslamhus-rectpacker/health.svg)](https://phpackages.com/packages/aslamhus-rectpacker)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
