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

Related tags

Miscellaneous grid
Overview

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)
A responsive image polyfill for , srcset, sizes, and more

Picturefill A responsive image polyfill. Authors: See Authors.txt License: MIT Picturefill has three versions: Version 1 mimics the Picture element pa

Scott Jehl 10k Dec 31, 2022
a responsive equal heights plugin

jquery.matchHeight.js matchHeight makes the height of all selected elements exactly equal brm.io/jquery-match-height Demo - Features - Gallery - Insta

null 3.1k Jan 5, 2023
A high-performance, dependency-free library for animated filtering, sorting, insertion, removal and more

MixItUp 3 MixItUp is a high-performance, dependency-free library for animated DOM manipulation, giving you the power to filter, sort, add and remove D

Patrick Kunka 4.5k Dec 24, 2022
JavaScript Survey and Form Library

SurveyJS is a JavaScript Survey and Form Library. SurveyJS is a modern way to add surveys and forms to your website. It has versions for Angular, jQue

SurveyJS 3.5k Jan 1, 2023
Extensive math expression evaluator library for JavaScript and Node.js

?? Homepage Fcaljs is an extensive math expression evaluator library for JavaScript and Node.js. Using fcal, you can perform basic arithmetic, percent

Santhosh Kumar 93 Dec 19, 2022
Browser fingerprinting library with the highest accuracy and stability.

FingerprintJS is a browser fingerprinting library that queries browser attributes and computes a hashed visitor identifier from them. Unlike cookies a

FingerprintJS 18.1k Dec 31, 2022
autoNumeric is a standalone library that provides live as-you-type formatting for international numbers and currencies.

What is autoNumeric? autoNumeric is a standalone Javascript library that provides live as-you-type formatting for international numbers and currencies

AutoNumeric 1.7k Dec 16, 2022
A platform detection library.

Platform.js v1.3.6 A platform detection library that works on nearly all JavaScript platforms. Disclaimer Platform.js is for informational purposes on

BestieJS Modules 3.1k Dec 31, 2022
A benchmarking library. As used on jsPerf.com.

Benchmark.js v2.1.4 A robust benchmarking library that supports high-resolution timers & returns statistically significant results. As seen on jsPerf.

BestieJS Modules 5.3k Dec 28, 2022
A wrapper library for Jitsi Meet that adds audio spatialization, to be able to create virtual meeting rooms.

A wrapper library for Jitsi Meet that adds audio spatialization, to be able to create virtual meeting rooms.

Sean T. McBeth 1.1k Dec 27, 2022
Solid.js library adding signaling to built-in non-primitives

This package provides signaled versions of Javascript's built-in objects. Thanks to it, all theirs properties will be automatically tracked while using standard API.

Maciej Kwaśniak 40 Dec 29, 2022
This library was designed to be used in SPA framework wrappers for the FingerprintJS Pro Javascript Agent

Framework-agnostic SPA service wrapper. Use it to build a FingerprintJS Pro wrapper for your favorite framework.

FingerprintJS 12 Sep 3, 2022
ChelseaJS - a Javascript library for creative, generative Coding

ChelseaJS is a Javascript library for creative, generative Coding. It's simple and intuitive syntax makes it easy for everyone (including non-coders)

Prakrisht Dahiya 26 Oct 6, 2022
Estrela - a JavaScript library for building reactive web components inspired by lit

Estrela ⭐ Full Reactive Web Components Estrela is a JavaScript library for building reactive web components inspired by lit. Just like Lit, Estrela is

null 50 Oct 31, 2022
📝 Algorithms and data structures implemented in JavaScript with explanations and links to further readings

JavaScript Algorithms and Data Structures This repository contains JavaScript based examples of many popular algorithms and data structures. Each algo

Oleksii Trekhleb 158k Dec 31, 2022
Gmail-like client-side drafts and bit more. Plugin developed to save html forms data to LocalStorage to restore them after browser crashes, tabs closings and other disasters.

Sisyphus Plugin developed to save html forms data to LocalStorage to restore them after browser crashes, tabs closings and other disasters. Descriptio

Alexander Kaupanin 2k Dec 8, 2022
A lightweight jQuery plugin for collapsing and expanding long blocks of text with "Read more" and "Close" links.

Readmore.js V3 alpha I am deprecating the 2.x version of Readmore.js. A new version is coming soon! Check it out and help me test it! Readmore.js A sm

Jed Foster 1.5k Nov 30, 2022
FriendAdvisor is a mobile app with a focus on allowing friends and family to coordinate and receive text notifications about upcoming group events.

FriendAdvisor is a mobile app with a focus on allowing friends and family to coordinate and receive text notifications about upcoming group events.

Brad Johnson 4 Sep 29, 2022
Defines the communication layer between mobile native(iOS/Android) and webview using JSON Schema and automatically generates SDK code

Defines the communication layer between mobile native(iOS/Android) and webview using JSON Schema and automatically generates SDK code.

당근마켓 31 Dec 8, 2022