An imaginary grid to make positioning and moving things easier.
- gridset
npm i gridset
import { Gridset } from 'gridset';
const grid = new Gridset({
width: 200, // <-- width of the grid
height: 200, // <-- height of the grid
rows: 5, // <-- number of rows
cols: 5, // <-- number of columns
});
You now have a Gridset. It looks like this:
βββββββ¬ββββββ¬ββββββ¬ββββββ¬ββββββ
β 0,0 β 1,0 β 2,0 β 3,0 β 4,0 β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β 0,1 β 1,1 β 2,1 β 3,1 β 4,1 β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β 0,2 β 1,2 β 2,2 β 3,2 β 4,2 β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β 0,3 β 1,3 β 2,3 β 3,3 β 4,3 β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β 0,4 β 1,4 β 2,4 β 3,4 β 4,4 β
βββββββ΄ββββββ΄ββββββ΄ββββββ΄ββββββ
Fun fact: this example was made with Gridset.
But Gridset does not actually render a grid. That part is up to you if you want to and it's easy.
There a few ways to get all of the cells of the gridset.
grid.cells
- a 2D array arranged by column where each column is an array of its row cells
grid.cols
- same as
grid.cells
- same as
grid.rows
- 2D array arranged by row where each row is an array of its column cells
grid.flatCells
- a flat array arranged by column
The imaginary cells generated by Gridset can can be located by column and row
indexes. So the first cell in our grid above is identified by .cell(0,0)
-
that's the cell at column 0, row 0.
When you retrieve a cell it looks like this:
{
x: x coordinate of the cell,
y: y coordinate of the cell,
w: width of the cell,
h: height of the cell,
t: top coordinate of the cell,
l: left coordinate of the cell,
r: right coordinate of the cell
b: bottom coordinate of the cell,
cx: center x coordinate of the cell,
cy: center y coordinate of the cell,
ri: row index of the cell,
ci: column index of the cell,
_u: () => one cell up,
_lu: () => one cell left and up,
_ru: () => one cell right and up,
_d: () => one cell down,
_ld: () => one cell left and down,
_rd: () => one cell right and down,
_r: () => one cell right,
_l: () => one cell left,
}
It is important to note that none of these are measured in pixels or inches or any other arbitrary unit. These are calculated values based on the parameters you used to initialize Gridset. Namely width, height, cols, and rows.
You can select an entire column of cells from your Gridset by calling
.col(columnIndex)
.
When you retrieve a column it looks like this:
{
x: x coordinate of the column,
y: y coordinate of the column,
w: width of the column,
h: height of the column,
t: top coordinate of the column,
l: left coordinate of the column,
r: right coordinate of the column
b: bottom coordinate of the column,
cx: center x coordinate of the column,
cy: center y coordinate of the column,
ci: index of the column,
cells: an array of the cells in the column
}
You can select an entire row of cells from your Gridset by calling
.row(rowIndex)
.
When you retrieve a row it looks like this:
{
x: x coordinate of the row,
y: y coordinate of the row,
w: width of the row,
h: height of the row,
t: top coordinate of the row,
l: left coordinate of the row,
r: right coordinate of the row
b: bottom coordinate of the row,
cx: center x coordinate of the row,
cy: center y coordinate of the row,
ci: index of the row,
cells: an array of the cells in the row
}
You can select a diagonal selection of cells from your Gridset by calling
.diagonal(columnIndex, rowIndex)
.
If our grid looked like this
βββββββ¬ββββββ¬ββββββ¬ββββββ¬ββββββ
β 0,0 β 1,0 β 2,0 β 3,0 β 4,0 β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β 0,1 β 1,1 β 2,1 β 3,1 β 4,1 β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β 0,2 β 1,2 β 2,2 β 3,2 β 4,2 β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β 0,3 β 1,3 β 2,3 β 3,3 β 4,3 β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β 0,4 β 1,4 β 2,4 β 3,4 β 4,4 β
βββββββ΄ββββββ΄ββββββ΄ββββββ΄ββββββ
And we called .diagonal(1, 2)
our result would be a flat array containing
[
.cell(0,0),
.cell(1,2),
.cell(2,3),
.cell(3,4),
]
Illustrated here:
βββββββ¬ββββββ¬ββββββ¬ββββββ¬ββββββ
β β β β β β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β 0,1 β β β β β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β β 1,2 β β β β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β β β 2,3 β β β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β β β β 3,4 β β
βββββββ΄ββββββ΄ββββββ΄ββββββ΄ββββββ
You can select a anti-diagonal selection of cells from your Gridset by calling
.antidiagonal(columnIndex, rowIndex)
.
If our grid looked like this
βββββββ¬ββββββ¬ββββββ¬ββββββ¬ββββββ
β 0,0 β 1,0 β 2,0 β 3,0 β 4,0 β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β 0,1 β 1,1 β 2,1 β 3,1 β 4,1 β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β 0,2 β 1,2 β 2,2 β 3,2 β 4,2 β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β 0,3 β 1,3 β 2,3 β 3,3 β 4,3 β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β 0,4 β 1,4 β 2,4 β 3,4 β 4,4 β
βββββββ΄ββββββ΄ββββββ΄ββββββ΄ββββββ
And we called .antidiagonal(1, 2)
our result would be a flat array containing
[
.cell(0,3),
.cell(1,2),
.cell(2,1),
.cell(3,0),
]
Illustrated here:
βββββββ¬ββββββ¬ββββββ¬ββββββ¬ββββββ
β β β β 3,0 β β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β β β 2,1 β β β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β β 1,2 β β β β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β 0,3 β β β β β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β β β β β β
βββββββ΄ββββββ΄ββββββ΄ββββββ΄ββββββ
An area is a group of cells defined by any two cells and composed of all the cells between them.
So an area made of cell 1,2 and cell 3,3 would look like this
βββββββ¬ββββββ¬ββββββ¬ββββββ¬ββββββ
β 0,0 β 1,0 β 2,0 β 3,0 β 4,0 β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β 0,1 β 1,1 β 2,1 β 3,1 β 4,1 β
βββββββΌββββββ΄ββββββ΄ββββββΌββββββ€
β 0,2 β β 4,2 β
βββββββ€ area βββββββ€
β 0,3 β β 4,3 β
βββββββΌββββββ¬ββββββ¬ββββββΌββββββ€
β 0,4 β 1,4 β 2,4 β 3,4 β 4,4 β
βββββββ΄ββββββ΄ββββββ΄ββββββ΄ββββββ
Fun fact: this example was made with Gridset.
You can select a group of cells from your Gridset by calling .area or .areaByCells. with cells that define two of the corners of the area you want to select in no particular order.
.areaByCells(cell1, cell2)
takes two cell objects, but it's really only
concerned about the ri
and ci
properties of each of them so if you don't
already have the cells you can use .area({ci1: 1, ri1: 2, ci2: 3 ri2: 3})
and
the result will be the same.
When you retrieve an area it looks like this:
{
x: x coordinate of the area,
y: y coordinate of the area,
w: width of the area,
h: height of the area,
t: top coordinate of the area,
l: left coordinate of the area,
r: right coordinate of the area
b: bottom coordinate of the area,
cx: center x coordinate of the area,
cy: center y coordinate of the area,
cells: a 2d array of the cells in the area (sub-grid)
}
Our grid is defined by width, height, number of columns and rows. Simple. But wait - there's more!
You can make the cells of the grid any size you want... even if they are bigger than the grid itself - which can get weird, but hey it's your grid.
Our 5 column grid looks like this
const grid = new Gridset({
width: 200,
height: 200,
rows: 5,
cols: 5,
});
0 40 80 120 160 200
ββββββββββ΄βββββββββ΄βββββββββ΄βββββββββ΄βββββββββ
ββββββββββ¬βββββββββ¬βββββββββ¬βββββββββ¬βββββββββ
β 0 β 1 β 2 β 3 β 4 β <- Row 0
ββββββββββ΄βββββββββ΄βββββββββ΄βββββββββ΄βββββββββ
Here the grid has been evenly divided into columns of 40 wide.
Let's add cellWidth.
const grid = new Gridset({
width: 200,
height: 200,
rows: 5,
cols: 5
cellWidth: 60
});
0 60 95 130 165 200
ββββββββββββββ΄ββββββββ΄ββββββββ΄ββββββββ΄ββββββββ
βββββββββββββΒ¦βββββββΒ¦βββββββΒ¦βββββββΒ¦ββββββββ
β Β¦ Β¦ Β¦ Β¦ β <- Row 0
βββββββββββββΒ¦βββββββΒ¦βββββββΒ¦βββββββΒ¦ββββββββ
β Β¦ Β¦ Β¦ Β¦ Β¦
β col0 Β¦ β Β¦ Β¦ Β¦
ββββββββββββββ β Β¦ Β¦ Β¦
Β¦ β β Β¦ Β¦ Β¦
Β¦ β col1 β Β¦ Β¦ Β¦
0 βββββββββββββ Β¦ Β¦ Β¦
Β¦ β Β¦ Β¦ Β¦
Β¦ β col2 Β¦ Β¦ Β¦
35 βββββββββββββ Β¦ Β¦
Β¦ β Β¦ Β¦
Β¦ β col3 Β¦ Β¦
70 βββββββββββββ Β¦
Β¦ β Β¦
Β¦ β col4 Β¦
105 βββββββββββββ
Β¦
Β¦
140
Our grid still has the correct width while respecting the custom cellWidth. In
order to achieve this our columns/cells now overlap. And it works the same way
with setting cellHeight
const grid = new Gridset({
width: 200,
height: 200,
rows: 5,
cols: 5
cellHeight: 60
});
0 β ββββββββββββββββ
β β β
β β β
β β row0 β------β¬---- 35
β β β β
60 β€ ββββββββββββββββ β
β β row1 β------β¬---- 70
β β β β
95 β€ βββββββββββββββββββββββ β
β β row2 β------β¬---- 105
β β β β
130 β€ ββββββββββββββββββββββββββββββ β
β β row3 β------β¬---- 140
β β β β
165 β€ βββββββββββββββββββββββββββββββββββββ β
β β row4 β
β β β
200 β ββββββββββββββββββββββββββββββββββββββββββββ
Each individual cell you retrieve comes with methods to retrieve its adjacent cells.
{
...,
_u: () => one cell up,
_lu: () => one cell left and up,
_ru: () => one cell right and up,
_d: () => one cell down,
_ld: () => one cell left and down,
_rd: () => one cell right and down,
_r: () => one cell right,
_l: () => one cell left,
}
So if we started with .cell(1,2)
.cell(1,2)._u()
will return
cell(1,1)
ββββββββββ¬βββββββββ¬βββββββββ¬βββββββββ
β β β β β
β 0,0 β 1,0 β 2,0 β 3,0 β
β β β β β
ββββββββββΌβββββββββΌβββββββββΌβββββββββ€
β β β β β
β 0,1 β 1,1 β 2,1 β 3,1 β
β β u β β β
ββββββββββΌβββββββββΌβββββββββΌβββββββββ€
β β β β β
β 0,2 β 1,2 β 2,2 β 3,2 β
β β * β β β
ββββββββββΌβββββββββΌβββββββββΌβββββββββ€
β β β β β
β 0,3 β 1,3 β 2,3 β 3,3 β
β β β β β
ββββββββββ΄βββββββββ΄βββββββββ΄βββββββββ
These methods can be chained together: cell(1,2)._u()._u()._r()
ββββββββββ¬βββββββββ¬βββββββββ¬βββββββββ
β β β β β
β 0,0 β 1,0 β 2,0 <----------- land here.
β β u β r β β
ββββββββββΌβββββββββΌβββββββββΌβββββββββ€
β β β β β
β 0,1 β 1,1 β 2,1 β 3,1 β
β β u β β β
ββββββββββΌβββββββββΌβββββββββΌβββββββββ€
β β β β β
β 0,2 β 1,2 β 2,2 β 3,2 β
β β * β β β
ββββββββββΌβββββββββΌβββββββββΌβββββββββ€
β β β β β
β 0,3 β 1,3 β 2,3 β 3,3 β
β β β β β
ββββββββββ΄βββββββββ΄βββββββββ΄βββββββββ
However if you run into the edge of the grid there will be no cell to retrieve in certain directions. For example, using the last example:
cell(1,2)._u()._u()._r()
If we added ._up()
we would be outside the grid. By default you will be
returned the same cell that you attempted to look from. In this case you will be
returned cell(2,0)
+--------+
| |
| u | <-- out of grid.
| |
ββββββββββ¬βββββββββ¬βββββββββ¬βββββββββ
β β β β β
β 0,0 β 1,0 β 2,0 <----------- so you get this cell instead.
β β u β r β β
ββββββββββΌβββββββββΌβββββββββΌβββββββββ€
β β β β β
β 0,1 β 1,1 β 2,1 β 3,1 β
β β u β β β
ββββββββββΌβββββββββΌβββββββββΌβββββββββ€
β β β β β
β 0,2 β 1,2 β 2,2 β 3,2 β
β β * β β β
ββββββββββΌβββββββββΌβββββββββΌβββββββββ€
β β β β β
β 0,3 β 1,3 β 2,3 β 3,3 β
β β β β β
ββββββββββ΄βββββββββ΄βββββββββ΄βββββββββ
Gridset can provide an alternative result which can be helpful in some cases.
Using look
with a mode of cycle
will use the current position and direction
to return the cell as though you came through the other side of the grid
whenever you went off the grid
const mode = 'cycle';
cell(1, 2)._u()._u()._r()._u(mode);
// OR because it can be difficult to know
// which "look" will go off the grid.
cell(1, 2)._u(mode)._u(mode)._r(mode)._u(mode);
+--------+
| |
| u3 | <-- out of grid.
| |
ββββββββββ¬βββββββββ¬βββββββββ¬βββββββββ
β β β β β
β 0,0 β 1,0 β 2,0 β 3,0 β
β β u2 β r β β
ββββββββββΌβββββββββΌβββββββββΌβββββββββ€
β β β β β
β 0,1 β 1,1 β 2,1 β 3,1 β
β β u β β β
ββββββββββΌβββββββββΌβββββββββΌβββββββββ€
β β β β β
β 0,2 β 1,2 β 2,2 β 3,2 β
β β * β β β
ββββββββββΌβββββββββΌβββββββββΌβββββββββ€
β β β β β
β 0,3 β 1,3 β 2,3 <----------- so you get this cell instead.
β β β β β
ββββββββββ΄βββββββββ΄βββββββββ΄βββββββββ
const mode = 'cycle';
cell(1, 2)._u(mode)._u(mode)._u(mode);
+--------+
| |
| u | <-- out of grid.
| |
ββββββββββ¬βββββββββ¬βββββββββ¬βββββββββ
β β β β β
β 0,0 β 1,0 β 2,0 β 3,0 β
β β u β β β
ββββββββββΌβββββββββΌβββββββββΌβββββββββ€
β β β β β
β 0,1 β 1,1 β 2,1 β 3,1 β
β β u β β β
ββββββββββΌβββββββββΌβββββββββΌβββββββββ€
β β β β β
β 0,2 β 1,2 β 2,2 β 3,2 β
β β * β β β
ββββββββββΌβββββββββΌβββββββββΌβββββββββ€
β β β β β
β 0,3 β 1,3 <---------------------- so you get this cell instead.
β β β β β
ββββββββββ΄βββββββββ΄βββββββββ΄βββββββββ
const mode = 'cycle';
cell(1, 2)._d(mode)._d(mode);
ββββββββββ¬βββββββββ¬βββββββββ¬βββββββββ
β β β β β
β 0,0 β 1,0 <--------------------- so you get this cell instead.
β β β β β
ββββββββββΌβββββββββΌβββββββββΌβββββββββ€
β β β β β
β 0,1 β 1,1 β 2,1 β 3,1 β
β β β β β
ββββββββββΌβββββββββΌβββββββββΌβββββββββ€
β β β β β
β 0,2 β 1,2 β 2,2 β 3,2 β
β β * β β β
ββββββββββΌβββββββββΌβββββββββΌβββββββββ€
β β β β β
β 0,3 β 1,3 β 2,3 β 3,3 β
β β d β β β
ββββββββββ΄βββββββββ΄βββββββββ΄βββββββββ
| |
| d | <-- out of grid.
| |
+--------+
const mode = 'cycle';
cell(1, 2)._r(mode)._r(mode)._r(mode);
ββββββββββ¬βββββββββ¬βββββββββ¬βββββββββ
β β β β β
β 0,0 β 1,0 β 2,0 β 3,0 β
β β β β β
ββββββββββΌβββββββββΌβββββββββΌβββββββββ€
β β β β β
β 0,1 β 1,1 β 2,1 β 3,1 β
β β β β β
ββββββββββΌβββββββββΌβββββββββΌβββββββββ€---------+
β β β β β |
β 0,2 β 1,2 β 2,2 β 3,2 β r | <-- out of grid.
β β‘ β * β r β r β |
ββββββββββΌβββββββββΌβββββββββΌβββββββββ€---------+
β β β β β β
β β----------------------------------- so you get this cell instead.
β β β β β
ββββββββββ΄βββββββββ΄βββββββββ΄βββββββββ
const mode = 'cycle';
cell(1, 2)._l(mode)._l(mode);
ββββββββββ¬βββββββββ¬βββββββββ¬βββββββββ
β β β β β
β 0,0 β 1,0 β 2,0 β 3,0 β
β β β β β
ββββββββββΌβββββββββΌβββββββββΌβββββββββ€
out of β β β β β
grid β 0,1 β 1,1 β 2,1 β 3,1 β
| β β β β β
+-------ββββββββββΌβββββββββΌβββββββββΌβββββββββ€
| β β β β β
| l β 0,2 β 1,2 β 2,2 β 3,2 <----- so you get this cell instead.
| β l β * β β β
+-------ββββββββββΌβββββββββΌβββββββββΌβββββββββ€
β β β β β
β 0,3 β 1,3 β 2,3 β 3,3 β
β β β β β
ββββββββββ΄βββββββββ΄βββββββββ΄βββββββββ
const mode = 'cycle';
cell(1, 2)._rd(mode)._rd(mode);
ββββββββββ¬βββββββββ¬βββββββββ¬βββββββββ
β β β β β
β 0,0 β 1,0 β 2,0 β 3,0 β
β β β β β
ββββββββββΌβββββββββΌβββββββββΌβββββββββ€
β β β β β
β 0,1 <-------------------------------- so you get this cell instead.
β β β β β
ββββββββββΌβββββββββΌβββββββββΌβββββββββ€
β β β β β
β 0,2 β 1,2 β 2,2 β 3,2 β
β β * β β β
ββββββββββΌβββββββββΌβββββββββΌβββββββββ€
β β β β β
β 0,3 β 1,3 β 2,3 β 3,3 β
β β β rd β β
ββββββββββ΄βββββββββ΄βββββββββ΄βββββββββ
| |
| rd | <-- out of grid.
| |
+--------+
The following cycle generators work similarly to cell cycling. When a cycle reaches the the last cell the next value will be on the opposite side of the cycled area.
Cycle any flat array of cells.
cycle
accepts the following arguments, all arguments are optional.
cells
- this is a flat array of cells to cycle through
- the default is
grid.flatCells
dir
f
(forwards) orr
(reverse)- the default is
f
startingIndex
- where in the array to begin the cycle
- the default is 0
Once your cycle generator is instantiated you can retrieve the next cell in the cycle by calling:
[generator].next().value.el
const cycle = grid.cycle(arrayOfCells, [dir, startingIndex])
const firstCell = cycle.next().value.el
const secondCell = cycle.next().value.el
const thirdCell = cycle.next().value.el
// ... and so on forever.
Cycle helper methods allow you to easily cycle identifiable areas of the grid like columns or rows.
const cycle = grid.cycle(args)
const firstCell = cycle.next().value.el
const secondCell = cycle.next().value.el
const thirdCell = cycle.next().value.el
// ... and so on forever.
Each cycle helper method accepts an optional dir
argument of f
(forwards) or r
(reverse). The default for dir
is f
. Each cycle method accepts an optional
startingIndex
argument representing where in the array of cells to begin the
cycle. The default for startingIndex is 0
const cycle = grid.cycleRow(rowIndex, [dir, startingIndex])
const firstCell = cycle.next().value.el
const cycle = grid.cycleCol(columnIndex, [dir, startingIndex])
const firstCell = cycle.next().value.el
const cycle = grid.cycleDiagonal(columnIndex, rowIndex, [dir, startingIndex])
const firstCell = cycle.next().value.el
const cycle = grid.cycleAntidiagonal(columnIndex, rowIndex, [dir, startingIndex])
const firstCell = cycle.next().value.el
The following scan generators cycle through cells and when reaching the last or first cell will begin cycling in the reverse direction. You can think of it as a linearly and infinite bounce.
.scanCells
allows you to scan any flat array of cells.
Scan helper methods allow you to easily scan identifiable areas of the grid like columns or rows.
const scan = grid.scan(args)
const firstCell = scan.next().value.el
const secondCell = scan.next().value.el
const thirdCell = scan.next().value.el
// ... and so on forever.
Each scan helper method accepts an optional dir
argument of f
(forwards) or r
(reverse). The default for dir
is f
. Each scan method accepts an optional
startingIndex
argument representing where in the array of cells to begin the
scan. The default for startingIndex is 0
const scan = grid.scanRow(rowIndex, [dir, startingIndex])
const firstCell = scan.next().value.el
const scan = grid.scanCol(colIndex, [dir, startingIndex])
const firstCell = scan.next().value.el
const scan = grid.scanDiagonal(colIndex, rowIndex, [dir, startingIndex])
const firstCell = scan.next().value.el
const scan = grid.scanAntidiagonal(colIndex, rowIndex, [dir, startingIndex])
const firstCell = scan.next().value.el
const bounce = grid.bounce(
area, // default = grid
sx, // default = 0,
sy // default = 0
)
βββββββ¬ββββββ¬ββββββ¬ββββββ¬ββββββ
β 0 β β β β β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β β 1 β β β β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β 8 β β 2 β β β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β β 7 β β 3 β β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β β β 6 β β 4 β
βββββββΌββββββΌββββββΌββββββΌββββββ€
β β β β 5 β β
βββββββ΄ββββββ΄ββββββ΄ββββββ΄ββββββ