README.md 9.75 KB
Newer Older
Pavel Reznikov's avatar
Pavel Reznikov committed
1
2
3
gridstack.js
============

Pavel Reznikov's avatar
Pavel Reznikov committed
4
5
gridstack.js is a jQuery plugin for widget layout. This is drag-and-drop multi-column grid. It allows you to build 
draggable responsive bootstrap v3 friendly layouts. It also works great with [knockout.js](http://knockoutjs.com)
Pavel Reznikov's avatar
Pavel Reznikov committed
6

Pavel Reznikov's avatar
readme    
Pavel Reznikov committed
7
Inspired by [gridster.js](http://gridster.net). Built with love.
Pavel Reznikov's avatar
Pavel Reznikov committed
8
9
10
11

Demo
====

Pavel Reznikov's avatar
Pavel Reznikov committed
12
Please visit http://troolee.github.io/gridstack.js/ for demo.
Pavel Reznikov's avatar
Pavel Reznikov committed
13
14
15
16


Usage
=====
Pavel Reznikov's avatar
readme    
Pavel Reznikov committed
17

Pavel Reznikov's avatar
Pavel Reznikov committed
18
19
## Requirements

Pavel Reznikov's avatar
Pavel Reznikov committed
20
* http://underscorejs.org (>= 1.7.0)
Pavel Reznikov's avatar
typo    
Pavel Reznikov committed
21
22
* http://jquery.com (>= 1.11.0) 
* http://jqueryui.com (>= 1.11.0). Minimum required components: Core, Widget, Mouse, Draggable, Resizable
Pavel Reznikov's avatar
Pavel Reznikov committed
23
* (Optional) http://knockoutjs.com (>= 3.2.0)
Pavel Reznikov's avatar
license    
Pavel Reznikov committed
24

Pavel Reznikov's avatar
Pavel Reznikov committed
25
26
27
## Basic usage

```html
28
29
30
31
32
<div class="grid-stack">
    <div class="grid-stack-item" 
        data-gs-x="0" data-gs-y="0" 
        data-gs-width="4" data-gs-height="2">
            <div class="grid-stack-item-content"></div>
Pavel Reznikov's avatar
Pavel Reznikov committed
33
    </div>
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
    <div class="grid-stack-item" 
        data-gs-x="4" data-gs-y="0" 
        data-gs-width="4" data-gs-height="4">
            <div class="grid-stack-item-content"></div>
    </div>
</div>

<script type="text/javascript">
$(function () {
    var options = {
        cell_height: 80,
        vertical_margin: 10
    };
    $('.grid-stack').gridstack(options);
});
</script>
Pavel Reznikov's avatar
Pavel Reznikov committed
50
51
```

Pavel Reznikov's avatar
Pavel Reznikov committed
52
53
## Options

Pavel Reznikov's avatar
Pavel Reznikov committed
54
55
56
- `animate` - turns animation on (default: `false`)
- `auto` - if `false` it tells to do not initialize existing items (default: `true`)
- `cell_height` - one cell height (default: `60`)
Pavel Reznikov's avatar
Pavel Reznikov committed
57
- `handle` - draggable handle selector (default: `'.grid-stack-item-content'`)
Pavel Reznikov's avatar
Pavel Reznikov committed
58
- `height` - maximum rows amount. Default is `0` which means no maximum rows
Pavel Reznikov's avatar
Pavel Reznikov committed
59
- `float` - enable floating widgets (default: `false`)
Pavel Reznikov's avatar
Pavel Reznikov committed
60
- `item_class` - widget class (default: `'grid-stack-item'`)
Pavel Reznikov's avatar
Pavel Reznikov committed
61
- `min_width` - minimal width. If window width is less grid will be shown in one-column mode (default: `768`)
Pavel Reznikov's avatar
Pavel Reznikov committed
62
- `placeholder_class` - class for placeholder (default: `'grid-stack-placeholder'`)
Pavel Reznikov's avatar
Pavel Reznikov committed
63
64
- `vertical_margin` - vertical gap size (default: `20`)
- `width` - amount of columns (default: `12`)
Pavel Reznikov's avatar
Pavel Reznikov committed
65

Pavel Reznikov's avatar
Pavel Reznikov committed
66
67
## Grid attributes

Pavel Reznikov's avatar
Pavel Reznikov committed
68
69
70
- `data-gs-animate` - turns animation on 
- `data-gs-width` - amount of columns
- `data-gs-height` - maximum rows amount. Default is `0` which means no maximum rows.
Pavel Reznikov's avatar
Pavel Reznikov committed
71

Pavel Reznikov's avatar
Pavel Reznikov committed
72
73
74
75
76
77
## Item attributes

- `data-gs-x`, `data-gs-y` - element position
- `data-gs-width`, `data-gs-height` - element size
- `data-gs-max-width`, `data-gs-min-width`, `data-gs-max-height`, `data-gs-min-height` - element constraints
- `data-gs-no-resize` - disable element resizing
Pavel Reznikov's avatar
Pavel Reznikov committed
78
- `data-gs-no-move` - disable element moving 
Pavel Reznikov's avatar
Pavel Reznikov committed
79
80
- `data-gs-auto-position` - tells to ignore `data-gs-x` and `data-gs-y` attributes and to place element to the first 
    available position
Pavel Reznikov's avatar
Pavel Reznikov committed
81
82
83
- `data-gs-locked` - the widget will be locked. It means another widgets couldn't move it during dragging or resizing.
The widget is still can be dragged or resized. You need to add `data-gs-no-resize` and `data-gs-no-move` attributes
to completely lock the widget.
Pavel Reznikov's avatar
Pavel Reznikov committed
84
85
86
    
## Events

Pavel Reznikov's avatar
Pavel Reznikov committed
87
### onchange(items)
Pavel Reznikov's avatar
Pavel Reznikov committed
88
89
90
91

Occurs when widgets change their position/size

```javascript
92
93
94
var serialize_widget_map = function (items) {
    console.log(items);
};
Pavel Reznikov's avatar
samples    
Pavel Reznikov committed
95

96
97
98
$('.grid-stack').on('change', function (e, items) {
    serialize_widget_map(items);
});
Pavel Reznikov's avatar
Pavel Reznikov committed
99
100
```

Pavel Reznikov's avatar
Pavel Reznikov committed
101
102
103
### ondragstart(event, ui)

```javascript
104
105
106
107
$('.grid-stack').on('dragstart', function (event, ui) {
    var grid = this;
    var element = event.target;
});
Pavel Reznikov's avatar
Pavel Reznikov committed
108
109
110
111
112
```

### ondragstop(event, ui)

```javascript
113
114
115
116
$('.grid-stack').on('dragstop', function (event, ui) {
    var grid = this;
    var element = event.target;
});
Pavel Reznikov's avatar
Pavel Reznikov committed
117
118
119
120
121
```

### onresizestart(event, ui)

```javascript
122
123
124
125
$('.grid-stack').on('resizestart', function (event, ui) {
    var grid = this;
    var element = event.target;
});
Pavel Reznikov's avatar
Pavel Reznikov committed
126
127
128
129
130
```

### onresizestop(event, ui)

```javascript
131
132
133
134
$('.grid-stack').on('resizestop', function (event, ui) {
    var grid = this;
    var element = event.target;
});
Pavel Reznikov's avatar
Pavel Reznikov committed
135
136
137
```


Pavel Reznikov's avatar
Pavel Reznikov committed
138
139
140
141
142
143
144
145
146
147
148
149
150
## API

### add_widget(el, x, y, width, height, auto_position)

Creates new widget.

Parameters:

- `el` - widget to add
- `x`, `y`, `width`, `height` - widget position/dimensions (Optional)
- `auto_position` - if `true` then `x`, `y` parameters will be ignored and widget will be places on the first available
position

Pavel Reznikov's avatar
Pavel Reznikov committed
151
152
153
Widget will be always placed even if result height will be more then grid height. You need to use `will_it_fit` method
before call `add_widget` for additional check.

Pavel Reznikov's avatar
Pavel Reznikov committed
154
```javascript
Pavel Reznikov's avatar
Pavel Reznikov committed
155
$('.grid-stack').gridstack();
Pavel Reznikov's avatar
Pavel Reznikov committed
156

Pavel Reznikov's avatar
Pavel Reznikov committed
157
var grid = $('.grid-stack').data('gridstack');
Pavel Reznikov's avatar
Pavel Reznikov committed
158
159
160
grid.add_widget(el, 0, 0, 3, 2, true);
```

161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
### cell_height()

Gets current cell height.

### cell_height(val)

Update current cell height. This method rebuilds an internal CSS stylesheet. Note: You can expect performance issues if
call this method too often.

```javascript
grid.cell_height(grid.cell_width() * 1.2);
```

### cell_width()

Gets current cell width.

Pavel Reznikov's avatar
Pavel Reznikov committed
178
179
180
181
182
183
184
### locked(el, val)

Locks/unlocks widget.

- `el` - widget to modify.
- `val` - if `true` widget will be locked. 

Pavel Reznikov's avatar
Pavel Reznikov committed
185
186
187
188
189
190
### remove_widget(el)

Removes widget from the grid.

Parameters:

Pavel Reznikov's avatar
samples    
Pavel Reznikov committed
191
- `el` - widget to remove
Pavel Reznikov's avatar
Pavel Reznikov committed
192

193
194
195
196
### remove_all()

Removes all widgets from the grid.

197
198
199
200
201
202
203
### resize(el, width, \[height\])

Changes widget size

Parameters:

- `el` - widget to resize
Pavel Reznikov's avatar
Pavel Reznikov committed
204
- `width`, `height` - new dimensions. If value is `null` or `undefined` it will be ignored.
205
206
207
208
209
210
211
212

### move(el, x, \[y\])

Changes widget position

Parameters:

- `el` - widget to move
Pavel Reznikov's avatar
Pavel Reznikov committed
213
- `x`, `y` - new position. If value is `null` or `undefined` it will be ignored.
214

215
216
217
218
219
220
221
222
223
224
225
226
### resizable(el, val)

Enables/Disables resizing.

- `el` - widget to modify
- `val` - if `true` widget will be resizable. 

### movable(el, val)

Enables/Disables moving.

- `el` - widget to modify
227
- `val` - if `true` widget will be draggable.
Pavel Reznikov's avatar
Pavel Reznikov committed
228
229
230
231
232
233
234
235
236
237
238

### will_it_fit(x, y, width, height, auto_position)

Returns `true` if the `height` of the grid will be less the vertical constraint. Always returns `true` if grid doesn't
have `height` constraint.

```javascript
if (grid.will_it_fit(new_node.x, new_node.y, new_node.width, new_node.height, true)) {
    grid.add_widget(new_node.x, new_node.y, new_node.width, new_node.height, true);
}
else {
Pavel Reznikov's avatar
typo    
Pavel Reznikov committed
239
    alert('Not enough free space to place the widget');
Pavel Reznikov's avatar
Pavel Reznikov committed
240
241
}
```
242
 
Pavel Reznikov's avatar
Pavel Reznikov committed
243

244
245
246
247
248
249
250
251
## Utils

### GridStackUI.Utils.sort(nodes, \[dir\], \[width\])

Sorts array of nodes

- `nodes` - array to sort
- `dir` - `1` for asc, `-1` for desc
Pavel Reznikov's avatar
Pavel Reznikov committed
252
- `width` - width of the grid. If `undefined` the width will be calculated automatically.
253

Pavel Reznikov's avatar
Pavel Reznikov committed
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
## Use with knockout.js

```javascript
ko.components.register('dashboard-grid', {
    viewModel: {
        createViewModel: function (params, componentInfo) {
            var ViewModel = function (params, componentInfo) {
                var grid = null;

                this.widgets = params.widgets;

                this.afterAddWidget = function (items) {
                    _.each(items, function (item) {
                        item = $(item);

                        if (grid == null) {
                            grid = $(componentInfo.element).find('.grid-stack').gridstack({
                                auto: false
                            }).data('gridstack');
                        }

                        grid.add_widget(item);
276
277
278
                        ko.utils.domNodeDisposal.addDisposeCallback(item[0], function () {
                            grid.remove_widget(item);
                        });
Pavel Reznikov's avatar
Pavel Reznikov committed
279
280
281
282
283
284
285
286
287
288
289
                    }, this);
                };

            };

            return new ViewModel(params, componentInfo);
        }
    },
    template: [
        '<div class="grid-stack">',
        '   <!-- ko foreach: widgets, afterRender: afterAddWidget -->',
Pavel Reznikov's avatar
Pavel Reznikov committed
290
291
292
293
294
        '       <div class="grid-stack-item" data-bind="attr: {',
        '               \'data-gs-x\': x, \'data-gs-y\': y,',
        '               \'data-gs-width\': width, \'data-gs-height\': height}">',
        '           <span data-bind="text: $index"></span>',
        '       </div>',
Pavel Reznikov's avatar
Pavel Reznikov committed
295
296
297
298
299
300
301
302
303
304
305
306
307
        '   <!-- /ko -->',
        '</div>'
    ].join('\n')
});
```

and HTML:

```html
<div data-bind="component: {name: 'dashboard-grid', params: $data}"></div>
```


308
309
310
Changes
=======

Pavel Reznikov's avatar
v0.2.2    
Pavel Reznikov committed
311
#### v0.2.2 (2014-12-23)
Pavel Reznikov's avatar
Pavel Reznikov committed
312

Pavel Reznikov's avatar
Pavel Reznikov committed
313
- fix grid initialization
314
- add `cell_height`/`cell_width` API methods
Pavel Reznikov's avatar
Pavel Reznikov committed
315
316
- fix boolean attributes (issue #31)

Pavel Reznikov's avatar
Pavel Reznikov committed
317
#### v0.2.1 (2014-12-09)
Pavel Reznikov's avatar
Pavel Reznikov committed
318

Pavel Reznikov's avatar
Pavel Reznikov committed
319
- add widgets locking (issue #19)
Pavel Reznikov's avatar
Pavel Reznikov committed
320
321
- add `will_it_fit` API method
- fix auto-positioning (issue #20)
Pavel Reznikov's avatar
Pavel Reznikov committed
322
- add animation (thanks to @ishields)
Pavel Reznikov's avatar
Pavel Reznikov committed
323
- fix `y` coordinate calculation when dragging (issue #18)
Pavel Reznikov's avatar
Pavel Reznikov committed
324
- fix `remove_widget` (issue #16)
Pavel Reznikov's avatar
Pavel Reznikov committed
325
- minor fixes
Pavel Reznikov's avatar
Pavel Reznikov committed
326
327


Pavel Reznikov's avatar
Pavel Reznikov committed
328
#### v0.2.0 (2014-11-30)
Pavel Reznikov's avatar
Pavel Reznikov committed
329

Pavel Reznikov's avatar
Pavel Reznikov committed
330
- add `height` option
Pavel Reznikov's avatar
Pavel Reznikov committed
331
- auto-generate css rules (widgets `height` and `top`)
Pavel Reznikov's avatar
Pavel Reznikov committed
332
333
- add `GridStackUI.Utils.sort` utility function
- add `remove_all` API method
334
- add `resize` and `move` API methods 
335
336
- add `resizable` and `movable` API methods
- add `data-gs-no-move` attribute
Pavel Reznikov's avatar
Pavel Reznikov committed
337
338
- add `float` option
- fix default css rule for inner content
Pavel Reznikov's avatar
Pavel Reznikov committed
339
- minor fixes
Pavel Reznikov's avatar
Pavel Reznikov committed
340

341
342
#### v0.1.0 (2014-11-18)

Pavel Reznikov's avatar
Pavel Reznikov committed
343
344
Very first version.

345

Pavel Reznikov's avatar
license    
Pavel Reznikov committed
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
License
=======

The MIT License (MIT)

Copyright (c) 2014 Pavel Reznikov

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.