Drag and drop library for two-dimensional, resizable and responsive lists

Overview

DEPRECATED

This project is no longer maintained, please consider using react-grid-layout instead.

GridList Build Status

Drag and drop library for a two-dimensional resizable and responsive list of items

Demo: http://hootsuite.github.io/grid/

The GridList library is split into two roles:

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

GridList class

Jump to:

API

new GridList(items, options)

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

The first constructor parameter is an array of items to populate the grid with.

Supported options:

  • direction - Can be 'horizontal' or 'vertical'. Defaults to 'horizontal'. 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()

myGrid.generateGrid();

Build the grid structure from scratch, using the positions of the given items. If items lack positional attributes (x and y), they will be misplaced, 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.

resizeGrid(lanes)

myGrid.resizeGrid(4);

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

  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.

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)

// Move item from [0, 0] to [1, 1]
var carefreeItem = myGrid.grid[0][0];
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,
  2. The position inside the item object 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.

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 the overlapped item(s). This is the preferred fair trade. If this doesn't work out and after swapping we still have collisions inside the grid, the entire grid will be regenerated, starting with the moved item fixed in its new position. In the latter case, all the items around and to the right of the moved item might have their position slightly altered.

resizeItem(item, size)

// Resize item from position [0, 0] to span over 3 columns
var growthItem = myGrid.grid[0, 0];

myGrid.resizeItem(growthItem, {w: 3});
console.log(growthItem.w); // will output "3"

myGrid.resizing(growthItem, {h: 2});
console.log(growthItem.h); // will output "2"

Resizing an item is very similar to moving its position, in the sense that grid cells will be repopulated and collisions will be handled afterwards. See moveItemToPosition.

Primitives

Item

The item is the building block of GridList, and is a plain JavaScript object. The primary function of the GridList is to position such items two-dimentionally. Which brings us to the composition of an item: w and h for size, x and y for position. E.g.

{w: 3, h: 1, x: 0, y: 1}

Note that x and y (column and row) are abstract coords inside the grid, they are integer values starting from 0. Naturally, w and h (width and height) also take up space in the same coordinate system, which reveals the smallest unit of a grid: the cell. You could say, for example, that the featured item above takes up three grid cells.

gridList.items

A GridList instance works around an array of items. The items array is the first parameter of the class constructor and is always visible under the .items property. Here's a list of items for a grid with three 1x1 items on a column with three rows:

[{w: 1, h: 1, x: 0, y: 0},
 {w: 1, h: 1, x: 0, y: 1},
 {w: 1, h: 1, x: 0, y: 2}]

gridList.grid

Seeing how JavaScript doesn't support multidimensional arrays, the 2d grid inside GridList is represented by an array for columns, with each array entry containing another array with cells for each row. The cell is simply a pointer to an item that occupies it, or a null reference if no item is sitting on that cell's position. Note that more cells can point to the same item reference, because items occupy w * h cells. Here's a grid pseudo-representation:

col1 col2 col3 col4
1 2
1 3 4 4
1 4 4

Having the grid in a two-dimensional data structure, we can fetch item references directly by targeting any of the cells they cover inside the grid. E.g.

myGrid.grid[1][0] // reference to item #2
myGrid.grid[1][1] // reference to item #3
myGrid.grid[2][1] // reference to item #4
myGrid.grid[3][2] // still reference to item #4

PS. This grid would be generated by these items:

[{w: 1, h: 3, x: 0, y: 0},
 {w: 1, h: 1, x: 1, y: 0},
 {w: 1, h: 1, x: 1, y: 1},
 {w: 2, h: 2, x: 2, y: 1}]

$.fn.gridList

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

The jQuery plugin has two main functions:

  • Render the GridList on top of a list of DOM elements. The list items are expected to have data-w and data-h attributes, and optionally data-x and data-y (if their positions have been previously generated and persisted)
  • Drag and drop capabilities

The function takes an optional argument with options that will be passed to the draggables when constructing them.

$('.my-list').gridList({lanes: 3}, {handle: '.title'});

See jQuery UI Draggable API for details on all the available options.

The rendered list is responsive to its parent container, meaning that the width and height of the items are calculated based on the container height divided by the number of grid rows.

FAQ: Why not gridster?

  • 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.
  • gridster works vertically while our solution works both vertically and horizontally.
  • Our lib contains over 5 times fewer code.
  • gridster collisions are very basic, 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.
  • 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.
  • 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. It also works for width=0.

Please check demo page or code directly for investigating these assumptions.

Comments
  • We need 3 features

    We need 3 features

    I compared your grid with gridster, your grid is very smart, also has a Good performance. But It has 3 important features Unrealized

    1. Dynamic creation(in codebehind)
    2. Drag resize
    3. Implement resizing of item height Look forward to your improved version,Thank you for your good ideas。
    opened by FreezeSoul 18
  • Implement vertical grid

    Implement vertical grid

    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

    So I took a stab at implementing vertical orientation... not as simple as suggested :)

    The code looks rather ugly at the moment and I'm sure lots of refactoring is needed, but I'd like to run it by you first to see if I'm on the right track.

    Vertical grids are created by specifying cols instead of rows, e.g.

    var myGrid = new GridList(items, {cols: 5});
    

    Demo page is here: http://gigablah.github.io/grid/index-vertical.html

    opened by gigablah 12
  • How to use with npm and webpack?

    How to use with npm and webpack?

    Similar to issue #98 I'm trying to work out how to use this with webpack directly from the npm package without much success.

    require('grid-list') loads the gridList.js ok, but jquery.gridList.js is not loaded.

    Following it up with require('grid-list/src/jquery.gridList.js') generates this error...

    ERROR in ./~/grid-list/src/jquery.gridList.js Module not found: Error: Cannot resolve module 'gridlist' in /home/john/project/node_modules/grid-list/src @ ./~/grid-list/src/jquery.gridList.js 6:4-43

    I've tried any number of incantations involving 'expose' and 'imports' without success. I confess I don't know the internals of what happens to do much more than take potshots in the dark.

    I do get success if I resolve.alias the two files in the webpack.config.js. With those in place I can just require both aliases and everything is good to go.

    resolve: {
       alias: {
           'gridlist': path.join(SRC_PATH, 'libs', 'gridList.js'),
           'jgridlist': path.join(SRC_PATH, 'libs', 'jquery.gridList.js')
       }
    }
    

    Just wondering if anyone has struck upon an incantation that will work without the aliases?

    opened by johnmee 7
  • Implement vertical gridlist

    Implement vertical gridlist

    Vertical gridlist

    In order to make the grid to support both vertical and horizontal directions we will modify its current implementation by adding new concepts #indexes and #lanes.

    Insert the image

    • [x] Modify rows prop to itemsPerLane, we no longer need a rows option If specified, itemsPerLane, will represent the #lanes
    • [x] Pass a custom option direction to identify the direction of the grid. By default will be horizontal. direction can be horizontal (default) or vertical
    • [x] Fix failing unit tests
    • [x] Add the fixtures for vertical grid as presented below

    Item per lane 2

    Image 2_items_per_lane

    Fixture

    itemsPerLane2: [
      {w: 1, h: 1, x: 0, y: 0},
      {w: 1, h: 1, x: 1, y: 0},
      {w: 1, h: 2, x: 0, y: 1},
      {w: 1, h: 1, x: 1, y: 1},
      {w: 1, h: 2, x: 1, y: 2},
      {w: 1, h: 1, x: 0, y: 3},
      {w: 0, h: 1, x: 0, y: 4},
      {w: 1, h: 1, x: 0, y: 5},
      {w: 1, h: 1, x: 1, y: 5},
      {w: 2, h: 2, x: 0, y: 6},
      {w: 2, h: 1, x: 0, y: 8},
    ]
    

    Resize flow from 2 lanes => 3 lanes and from 3 lanes => 4 lanes image2

    Item per lane 3

    Image 3_items_per_lane

    Fixture

    itemsPerLane3: [
      {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: 0, 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}
    ]
    

    Resize flow from 3 lanes => 2 lanes and from 3 lanes => 4 lanes

    image3

    Item per lane 4

    Image 4_items_per_lane

    Fixture

    itemsPerLane4: [
      {w: 2, h: 1, x: 0, y: 0},
      {w: 1, h: 1, x: 2, y: 0},
      {w: 1, h: 2, x: 3, y: 0},
      {w: 2, h: 2, x: 0, y: 1},
      {w: 1, h: 2, x: 2, y: 1},
      {w: 1, h: 1, x: 3, y: 2},
      {w: 0, h: 1, x: 0, y: 3},
      {w: 2, h: 1, x: 0, y: 4},
      {w: 1, h: 1, x: 2, y: 4},
      {w: 1, h: 1, x: 3, y: 4},
      {w: 1, h: 2, x: 0, y: 5},
      {w: 1, h: 1, x: 1, y: 5},
      {w: 2, h: 1, x: 2, y: 5},
      {w: 2, h: 1, x: 1, y: 6},
      {w: 1, h: 1, x: 3, y: 6}
    ]
    

    Resize flow from 4 lanes => 5 lanes and from 4 lanes => 3 lanes

    image4


    • [x] Test that items are correctly positioned withing the grid when direction = vertical
    • [x] Write the code which will position the items for vertical direction, ensure that unit test passed.
    • [ ] Further Todos
      • [ ] tests
        • [ ] Write tests for collisions
        • [ ] Write tests for item resize
        • [ ] Write tests for grid changes
        • [ ] Write tests for horizontal "timelines"
      • [ ] implementation
        • [ ] adapt _tryToResolveCollisionsLocally and _pullItemsToLeft for vertical grid
        • [ ] refactor _adjustHeightOfItems to both directions

    #lanes are rows or columns based on the direction. Lanes represent the fixed dimension of the grid.

    #indexes = represent the variable dimension of the grid.

    grid[index][lane]

    enhancement 
    opened by catalinmiron 6
  • resizeGrid() and data-x data-y attr location update

    resizeGrid() and data-x data-y attr location update

    Well done with the update the plugin is better then ever man!

    I just have one question. I am building a dashboard with dynamically generated

  • the li will not contain data-x and data-y I am trying to use the resizeGrid() function specified within the README but i cannot get it to work it says function not defined. $('#grid').GridList.resizeGrid('5'); I am using that to call the function.

    I also need to save layout I am calling $("#myGrid").data('_gridList').gridList and it renders the array. is there a way to assign data-x and data-y to the dynamilcally inserted li's so these can be saved ? or how can I assign the $("#myGrid").data('_gridList').gridList OBJECT to my

  • Thanks in advance.

  • opened by matpulis 5
  • Resizing an item can leave empty horizontal spaces

    Resizing an item can leave empty horizontal spaces

    bug3

    Solution

    When an item is resized we check if it fits in its original position. If it doesn't we start looking for a new position for it trying to preserve it's original row. If we can't find any, we make a new column and try to place it on its original row. If it doesn't fit there, we place it on the first row.

    However, there might be horizontal to the left of the new position. We need to call gravity to fix this. See #65 for extra details.

    TODO

    • [x] writing failing test
    • [x] call pullToLeft after the item is resized
    bug 
    opened by andrei-picus-hs 4
  • findLeftMostPositionForItem logic is flawed

    findLeftMostPositionForItem logic is flawed

    bug

    Solution

    The _findLeftMostPositionForItem method is only checking for items on the same row as the given item. We should change it to check for items across the entire height of the item.

    for (var j = item.y; j < item.y + item.h; j++) {
      var otherItem = this.grid[i][j];
    }
    

    TODO

    • [x] write tests that fail
    • [x] fix tests
    bug 
    opened by andrei-picus-hs 4
  • How is it responsive?

    How is it responsive?

    I don't know if I understood correctly what the README says, maybe I'm missing something, but how the grid would possibly be responsive if the items width and height are based onde the container? Do I have to set a fixed height to the container?

    I'm asking because I'm trying to make a few samples and it always appear with the same size, no matter the screen width or height.

    opened by LulzAugusto 4
  • Add support for saving and loading layout

    Add support for saving and loading layout

    As the API page is unavailable, I do not know if already exists. But what happens after the user customizes the page layout? Is there any way to save this layout and retrieve later?

    opened by drma-dev 4
  • Add extraColumns option

    Add extraColumns option

    Had 2 reasons for needing this...

    • I have a read-only mode that the user can toggle to edit mode, and the extra column doesn't look good when in the first mode.
    • My default width for new items is 2 (with the option to resize to 1), so by default users can't drag items to the extra column (never drags past the 50% mark). Being able to configure it to 2 extra columns fixes the issue.
    opened by bfischer1121 4
  • Warning when installing grid-list from npm

    Warning when installing grid-list from npm

    Scenario

    Given I add grid-list to my package.json file
    When install it
    Then I get the warning "npm WARN package.json [email protected] No repository field."
    

    Solution

    • [x] add the repo field in package.json

    https://www.npmjs.org/doc/files/package.json.html#repository

    opened by palcu 4
  • Not working in NodeApp

    Not working in NodeApp

    I have created a New Node App in my Plesk Control Panel and Uploaded the grid-master folder, Now I get only the GitHub Button Rendered on the Screen the Grid is not working here, But when I upload the Folder into an non Node App Domain fo example as an folder in some Wordpress Project and open it https://wpproject.com/grid-master ......Here I get the correct demo like the one from Hootsuite anyone know what the issue is and why I can not use this in my Node App? Thanks

    opened by ivanjeremic 0
  • Acessing the underlying GridList object from jQuery plugin

    Acessing the underlying GridList object from jQuery plugin

    I was wondering if anyone knew of any way to access the GridList object from a jQuery method call? I'm trying to find the position array and am having some trouble.

    opened by KatamariJr 0
  • change direction to ltr and rtl

    change direction to ltr and rtl

    Hi team, first of all a big thx to the great plugin.

    currently i m working with some application that have ltr and rtl option. For dashboard i m using our own grid plugin :-) . But when i switch to rtl its not working. How to achieve this function with grid.

    opened by ramthenmala 0
  • this._adjustSizeOfItems is not a function

    this._adjustSizeOfItems is not a function

    Hello and thanks for this package, i really liked it and i've been trying to get it working for almost 2 days i've webpack and i had this error coming from the package code: this._adjustSizeOfItems is not a function and this is the files content

    app.js:

    window.$ = require('jquery');
    require('jquery-ui');
    require('../../../vendor/tcg/voyager/resources/assets/js/app');
    window.gridList = require('grid-list')($);
    require('./gallery');
    

    gallery.js:

    $(document).ready(function() {
        $('#grid').gridList({
            lanes: 3,
            widthHeightRatio: 264 / 294,
            heightToFontSizeRatio: 0.25,
        });
    });
    

    html:

    <div id="grid">
        <div id="grid_item">
            <p>1</p>
        </div>
        <div class="grid-item">
            <p>1</p>
        </div>
    </div> 
    <script type="text/javascript" src="app.js"></script>
    

    package.json:

    "grid-list": "0.4.1",
    "jquery": "3.2.1",
    "jquery-ui": "1.12.1"
    

    any help is appreciated

    opened by husseinelhussein 0
Releases(v0.4.0)
Reorderable drag-and-drop lists for modern browsers and touch devices. No jQuery or framework required.

Sortable Sortable is a JavaScript library for reorderable drag-and-drop lists. Demo: http://sortablejs.github.io/Sortable/ Features Supports touch dev

SortableJS 26.1k Jan 5, 2023
A lightweight (~2kB) library to create range sliders that can capture a value or a range of values with one or two drag handles

range-slider-input A lightweight (~2kB) library to create range sliders that can capture a value or a range of values with one or two drag handles. Ex

Utkarsh Verma 42 Dec 24, 2022
A Drag-and-Drop library for all JavaScript frameworks implementing an enhanced transformation mechanism to manipulate DOM elements

JavaScript Project to Manipulate DOM Elements DFlex A Drag-and-Drop library for all JavaScript frameworks implementing an enhanced transformation mech

DFlex 1.5k Jan 8, 2023
Nested Sort is a JavaScript library which helps you to sort a nested list of items via drag and drop.

Nested Sort Nested Sort is a vanilla JavaScript library, without any dependencies, which helps you to sort a nested list of items via drag and drop. U

Hesam Bahrami 40 Dec 7, 2022
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023
Digispark Overmaster : free IDE TOOL allows to create and edit Digispark Scripts by the drag and drop technique,with cool GUI and easy to use it

Digispark_Overmaster Digispark Overmaster : free IDE TOOL allows to create and edit Digispark Scripts by the drag and drop technique,with cool GUI and

Yehia Elborma 5 Nov 14, 2022
DoMe is a ToDo App. you can add, delete and reorder elements of the todo list using drag and drop. You can also toggle between dark&light mode

DO ME Todo App Live Preview : DO ME Built With : - ReactJS - TailwindCSS Make sure you have: - Git - Nodejs version 14 or higher (we recommend using

Medjahdi Islem 5 Nov 18, 2022
An interactive app that allows adding, editing and removing tasks of a to-do list. Drag-and-drop featured added. Webpack was used to bundle all the Js modules in to one main Js file.

To-do List A to-do list app This app let you to set your own to-do list. Built With HTML CSS JavaScript WebPack Jest Live Page Page Link Getting Start

Kenny Salazar 7 May 5, 2022
Fancytree - JavaScript tree view / tree grid plugin with support for keyboard, inline editing, filtering, checkboxes, drag'n'drop, and lazy loading

Fancytree Fancytree (sequel of DynaTree 1.x) is a JavaScript tree view / tree grid plugin with support for keyboard, inline editing, filtering, checkb

Martin Wendt 2.6k Jan 9, 2023
Drag and drop Argo Workflows tool.

Visual Argo Workflows Live demo The goal of this project is to make it easier for everyone on a team to construct and run their own workflows. Workflo

Artem Golub 38 Dec 22, 2022
Allow moving/copying/and creation embeds for blocks with drag-n-drop just like Logseq or Roam

Demo Features Drag-n-drop for list items in the same pane and between different panes 3 modes: move block, copy block, embed block Automatic reference

null 92 Dec 26, 2022
Drag-and-drop editor for Docassemble interviews

GraphDoc Introduction GraphDoc is a web-application that has been developed on behalf of the Maastricht Law & Tech Lab, which is part of Maastricht Un

Maastricht Law & Tech Lab 16 Dec 28, 2022
🔖 A drag-and-drop form builder for Bootstrap 4.

Bootstrap v4 Form Builder A drag-and-drop form builder for Bootstrap 4. ❓ Get Help There are few ways to get help: Please post questions on Stack Over

Bloggify 107 Dec 22, 2022
Zero Two Bot,A fully Modular Whatsapp Bot to do everything possible in WhatsApp by Team Zero Two

?? ???????? ?????? ???? ?? A Moduler WhatsApp Bot designed for both PM and Groups - To take your boring WhatsApp usage into a whole different level. T

Sam Pandey 69 Dec 25, 2022
Tiny js library to make DOM elements movable and resizable .

resizedrag.js Tiny js library to make DOM elements movable and resizable . Demo Here . This library has added resizing functionalities to the existing

null 4 Mar 28, 2022
A JavaScript library allowing the creation of manually resizable div elements.

Resizable.js A JavaScript library allowing the creation of resizable html divs. Try the live demo! Setup Link to both resizable.js and resizable-style

null 44 Oct 6, 2022
k-means algorithm module for n-dimensional data

K-Means Algorithm This module allows you to compute the k-Means algorithm with n-dimensional data. You simply put in your data as a list and the k you

null 3 Jan 31, 2022