Skip to content
This repository has been archived by the owner on Feb 3, 2022. It is now read-only.

Commit

Permalink
Merge pull request #62 from uberVU/62-implement-vertical-gridlist
Browse files Browse the repository at this point in the history
Implement vertical gridlist
  • Loading branch information
andrei-picus-hs committed Aug 25, 2015
2 parents b20267d + e147f70 commit 6575da0
Show file tree
Hide file tree
Showing 11 changed files with 412 additions and 207 deletions.
78 changes: 41 additions & 37 deletions README.md
Expand Up @@ -5,20 +5,13 @@ items

**Demo: http://ubervu.github.io/grid/**

**Disclaimer: The current implementation is for a horizontal grid. This means
that the number of rows is configurable, whereas columns extend dynamically,
based on the number, size and position of items placed inside the grid.** While
this is by design, most, if not all, logic was built around the idea that at
any point the other axis could be supported with minor/moderate code changes,
making both orientations available through the use of an single option.

The GridList library is split into two roles:

1. An agnostic [**GridList class**](#gridlist-class) that manages the
two-dimensional positions from a list of items within a virtual matrix
two-dimensional positions from a list of items within a virtual matrix.
2. A [**jQuery plugin**](#fngridlist) built on top of the GridList class
that translates the generic items positions into responsive DOM elements with
drag and drop capabilities
drag and drop capabilities.

## GridList class

Expand All @@ -32,15 +25,23 @@ Jump to:
#### new GridList(items, options)

```js
var myGrid = new GridList(items, {rows: 3});
var myGrid = new GridList(items, {
direction: 'horizontal',
lanes: 3
});
```

The first constructor parameter is an array of [items](#primitives) to populate
the grid with.

Supported options:

- **rows** - Number of rows for the grid
- **direction** - Can be `'horizontal'` or `'vertical'`. Defaults to
`'vertical'`. This sets how the grid can expand e.g. for 'horizontal' the
grid will stretch towards the right to accommodate all the items. For
'vertical', it will stretch towards the bottom.
- **lanes** - Number of fixed rows or columns, depending on the
direction.

#### generateGrid()

Expand All @@ -54,22 +55,22 @@ possibly overlapping. If you want to build a grid around a list of items that
only have their size attributes defined (w and h), and rely on the library to
position them two-dimensionally, use [_resizeGrid._](#resizegridrows)

#### resizeGrid(rows)
#### resizeGrid(lanes)

```js
myGrid.resizeGrid(4);
```

(Re)generate positions for the items inside a grid instance for a given number
of rows. This method has two major use-cases:
of rows/columns. This method has two major use-cases:

1. Items are being represented two-dimensionally for the first time
1. Items are being represented two-dimensionally for the first time.
2. Items already have 2d positions but need to be represented on a different
grid size, maintaining as much as possible of their previous order
grid size, maintaining as much as possible of their previous order.

Given the horizontal orientation, positions inside the grid are generated
left-to-right, top-to-bottom. So when looking for a new position inside the
grid the topmost row from the leftmost column is chosen.
Positions inside the grid are generated left-to-right, top-to-bottom. So when
looking for a new position inside the grid the topmost row from the leftmost
column is chosen.

#### moveItemToPosition(item, position)

Expand All @@ -81,11 +82,11 @@ myGrid.moveItemToPosition(carefreeItem, [1, 1]);

Here are things that happen when moving an item inside the grid:

1. The item's previous position is cleared inside the [2d grid](#gridlistgrid)
2. The position inside the [item object](#item) is updated
3. The item's new position is marked inside the 2d grid
1. The item's previous position is cleared inside the [2d grid](#gridlistgrid),
2. The position inside the [item object](#item) is updated,
3. The item's new position is marked inside the 2d grid and
4. Collisions are handled if the moved item overlaps with other item(s) from
the grid
the grid.

Collisions can be solved in two ways. First, an attempt to resolve them
_locally_ is made, meaning that the moved item tries to swap position with
Expand Down Expand Up @@ -184,7 +185,10 @@ PS. This grid would be generated by these items:
## $.fn.gridList

```js
$('.my-list').gridList({rows: 3});
$('.my-list').gridList({
direction: 'horizontal',
lanes: 3
});
```

The jQuery plugin has two main functions:
Expand All @@ -198,7 +202,7 @@ The function takes an optional argument with options that will be passed to the
draggables when constructing them.

```js
$('.my-list').gridList({rows: 3}, {handle: '.title');
$('.my-list').gridList({lanes: 3}, {handle: '.title');
```
See [jQuery UI Draggable API](api.jqueryui.com/draggable/) for details on all
Expand All @@ -211,22 +215,22 @@ divided by the number of grid rows.
## FAQ: Why not [gridster](https://github.com/ducksboard/gridster.js)?
- Their README reads Ducksboard is no longer active in their development. There
are a few notable forks but it's hard to assert their [reliability.](https://github.com/dustmoo/gridster.js/issues)
- gridster works vertically and our design is horizontal. We instigated a
gridster pull request that attempted to make gridster work both ways and it
didn't seem to stabilize any time soon, plus the code was too complex to
approach. Our lib ended up having over than 5 times fewer code.
- gridster collisions are [very basic](https://github.com/ducksboard/gridster.js/issues/54),
we pushed towards better UX and found alternative ways for dealing with
collisions.
are a few notable forks but it's hard to assert their
[reliability.](https://github.com/dustmoo/gridster.js/issues)
- gridster works vertically while our solution works both vertically and
horizontally.
- Our lib contains over 5 times fewer code.
- gridster collisions are [very
basic](https://github.com/ducksboard/gridster.js/issues/54), we pushed towards
better UX and found alternative ways for dealing with collisions.
- We wanted out-of-the-box responsiveness, and the entire grid system was build
fluid, relative to any parent container.
fluid, relative to any parent container.
- We needed the grid logic to be a DOM-less lib outside the jQuery plugin. This
allows us to compute grid positions on the server-side and run kick-ass fast
tests with Node.
allows us to compute grid positions on the server-side and run kick-ass fast
tests with Node.
- Another more particular thing we needed was widgets that had height=0, which
means they stretch on however many rows a grid has. We show timelines like
this. The same can be easily adapted for width in vertical grids.
means they stretch on however many rows a grid has. We show timelines like
this. It also works for width=0.
*Please check [demo page](http://ubervu.github.io/grid/) or code directly for
investigating these assumptions.*
4 changes: 2 additions & 2 deletions demo/load.js
Expand Up @@ -31,7 +31,7 @@ var DemoGrid = {
if (size) {
this.currentSize = size;
}
$('#grid').gridList('resize', this.currentSize);
$('#grid').gridList('reflow');
},
flashItems: function(items) {
// Hack to flash changed items visually
Expand All @@ -54,7 +54,7 @@ $(function() {
DemoGrid.buildElements($('#grid'), fixtures.DEMO);

$('#grid').gridList({
rows: DemoGrid.currentSize,
lanes: DemoGrid.currentSize,
widthHeightRatio: 264 / 294,
heightToFontSizeRatio: 0.25,
onChange: function(changedItems) {
Expand Down
3 changes: 1 addition & 2 deletions demo/style.css
Expand Up @@ -12,8 +12,7 @@ body {
left: 0;
right: 10px;
bottom: 0;
overflow-x: auto;
overflow-y: hidden;
overflow: auto;
}
.grid {
position: relative;
Expand Down
10 changes: 5 additions & 5 deletions spec/findPositionForItemSpec.js
Expand Up @@ -16,7 +16,7 @@ describe("findPositionForItem", function() {
var grid;

beforeEach(function() {
grid = new GridList([], {rows: 2});
grid = new GridList([], {lanes: 2});
});

it("should place it at the top", function() {
Expand All @@ -36,7 +36,7 @@ describe("findPositionForItem", function() {
var grid;

beforeEach(function() {
grid = new GridList([{x: 0, y: 0, w: 1, h: 1}], {rows: 2});
grid = new GridList([{x: 0, y: 0, w: 1, h: 1}], {lanes: 2});
});

it("should place it at after the rest of the elements", function() {
Expand All @@ -58,7 +58,7 @@ describe("findPositionForItem", function() {
beforeEach(function() {
grid = new GridList(
[{x: 0, y: 0, w: 1, h: 1}, {x: 0, y: 1, w: 1, h: 1}],
{rows: 2});
{lanes: 2});
});

it("should place it on a new column on the row I tell it to", function() {
Expand All @@ -81,7 +81,7 @@ describe("findPositionForItem", function() {
var grid;

beforeEach(function() {
grid = new GridList([], {rows: 2});
grid = new GridList([], {lanes: 2});
});

it("should place it at the top", function() {
Expand All @@ -101,7 +101,7 @@ describe("findPositionForItem", function() {
var grid;

beforeEach(function() {
grid = new GridList([{x: 0, y: 0, w: 1, h: 1}], {rows: 2});
grid = new GridList([{x: 0, y: 0, w: 1, h: 1}], {lanes: 2});
});

it("should place it on a new column at the top", function() {
Expand Down
21 changes: 21 additions & 0 deletions spec/fixtures.js
Expand Up @@ -111,6 +111,7 @@ fixtures.GRID2 = {
]
};


fixtures.DEMO = [
{w: 1, h: 1, x: 0, y: 0},
{w: 1, h: 2, x: 0, y: 1},
Expand All @@ -131,6 +132,26 @@ fixtures.DEMO = [
{w: 1, h: 1, x: 10, y: 2}
];

fixtures.verticalGridDemo = [
{w: 1, h: 1, x: 0, y: 0},
{w: 1, h: 1, x: 1, y: 0},
{w: 1, h: 1, x: 2, y: 0},
{w: 2, h: 1, x: 0, y: 1},
{w: 1, h: 1, x: 2, y: 1},
{w: 3, h: 1, x: 0, y: 2},
{w: 1, h: 2, x: 0, y: 3},
{w: 1, h: 1, x: 1, y: 3},
{w: 1, h: 1, x: 2, y: 3},
{w: 1, h: 1, x: 1, y: 4},
{w: 1, h: 1, x: 2, y: 4},
{w: 2, h: 1, x: 0, y: 5},
{w: 1, h: 2, x: 2, y: 5},
{w: 1, h: 1, x: 0, y: 6},
{w: 1, h: 1, x: 1, y: 6},
{w: 2, h: 2, x: 0, y: 7},
{w: 1, h: 2, x: 2, y: 7}
];

// Enable Node module
if (typeof(require) == 'function') {
for (var k in fixtures) {
Expand Down
10 changes: 5 additions & 5 deletions spec/gridChangesSpec.js
Expand Up @@ -18,7 +18,7 @@ describe("Grid changes", function() {
it("should return 0 items between same snapshots", function() {
var gridFixture = fixtures.GRID2.rows3,
grid = new GridList(GridList.cloneItems(gridFixture), {
rows: 3
lanes: 3
});
helpers.addIndexesToItems(grid.items);

Expand All @@ -28,7 +28,7 @@ describe("Grid changes", function() {
it("should return 0 items after moving item to same position", function() {
var gridFixture = fixtures.GRID2.rows3,
grid = new GridList(GridList.cloneItems(gridFixture), {
rows: 3
lanes: 3
});
helpers.addIndexesToItems(grid.items);
var snapshot = GridList.cloneItems(grid.items);
Expand All @@ -40,7 +40,7 @@ describe("Grid changes", function() {
it("should return only the horizontally swapped items", function() {
var gridFixture = fixtures.GRID2.rows3,
grid = new GridList(GridList.cloneItems(gridFixture), {
rows: 3
lanes: 3
});
helpers.addIndexesToItems(grid.items);
var initialItems = GridList.cloneItems(grid.items);
Expand All @@ -56,7 +56,7 @@ describe("Grid changes", function() {
it("should return only the vertically swapped items", function() {
var gridFixture = fixtures.GRID2.rows3,
grid = new GridList(GridList.cloneItems(gridFixture), {
rows: 3
lanes: 3
});
helpers.addIndexesToItems(grid.items);
var initialItems = GridList.cloneItems(grid.items);
Expand All @@ -73,7 +73,7 @@ describe("Grid changes", function() {
it("should return all items following resized item (to its right)", function() {
var gridFixture = fixtures.GRID2.rows3,
grid = new GridList(GridList.cloneItems(gridFixture), {
rows: 3
lanes: 3
});
helpers.addIndexesToItems(grid.items);
var initialItems = GridList.cloneItems(grid.items);
Expand Down

0 comments on commit 6575da0

Please sign in to comment.