Skip to content

Commit 6d122cd

Browse files
authored
Merge pull request #1621 from adumesny/develop
collision overall - support for swap
2 parents 98aa68e + 270dde4 commit 6d122cd

File tree

9 files changed

+433
-243
lines changed

9 files changed

+433
-243
lines changed

doc/CHANGES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ Change log
5050
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
5151
## 3.3.0-dev
5252

53+
- fix [#149](https://github.com/gridstack/gridstack.js/issues/149) [#1094](https://github.com/gridstack/gridstack.js/issues/1094) [#1605](https://github.com/gridstack/gridstack.js/issues/1605) re-write of the **collision code**! you can now swap items of the same size (vertical/horizontal) when grid is full, and is the default in `float:false` (top gravity) as it feels more natural. Could add Alt key for swap vs push behavior later.<br>
54+
Dragging up and down now behave the same (used to require push WAY down past to swap/append). Also much more efficient collision code.<br>
55+
Still TODO: handle mid point of dragged over items rather 50% of row/column and check for the most covered when multiple items collide.
5356
- fix [1617](https://github.com/gridstack/gridstack.js/issues/1617) FireFox DOM order issue. Thanks [@marcel-necker](https://github.com/marcel-necker)
5457

5558
## 3.3.0 (2021-2-2)

spec/e2e/html/141_1534_swap.html

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1">
7+
<title>swap demo</title>
8+
9+
<link rel="stylesheet" href="../../../demo/demo.css"/>
10+
<script src="../../../dist/gridstack-h5.js"></script>
11+
12+
</head>
13+
<body>
14+
<div class="container-fluid">
15+
<h1>Swap collision demo</h1>
16+
<div>
17+
<a class="btn btn-primary" onClick="addNewWidget()" href="#">Add Widget</a>
18+
<a class="btn btn-primary" onclick="toggleFloat()" id="float" href="#"></a>
19+
<a class="btn btn-primary" onclick="toggleMax()" id="max" href="#"></a>
20+
<a class="btn btn-primary" onclick="toggleBigger()" id="big" href="#"></a>
21+
</div>
22+
<br><br>
23+
<div class="grid-stack"></div>
24+
</div>
25+
<script src="../../../demo/events.js"></script>
26+
<script type="text/javascript">
27+
let floatButton = document.getElementById('float');
28+
let maxButton = document.getElementById('max');
29+
let bigButton = document.getElementById('big');
30+
let size = 1;
31+
32+
let grid = GridStack.init({float: false, cellHeight: 70, maxRow: 0});
33+
addEvents(grid);
34+
35+
let count = 0;
36+
let items = [
37+
{x:0, y:0}, {x:0, y:1}, {x:0, y:2},{x:1, y:0}, {x:1, y:1}, {x:1, y:2},
38+
{x:5, y:0}, {x:4, y:1, w:3, locked: false, _content: 'locked'}, {x:5, y:2},
39+
{x:7, y:0}, {x:8, y:0}, {x:9, y:0}, {x:7, y:1, w:3}, {x:8, y:2},
40+
{x:11, y:0}, {x:11, y:1, h:2},
41+
];
42+
items.forEach(n => {n.id = count; n.content = n.content || String(count); count++})
43+
grid.load(items);
44+
45+
addNewWidget = function() {
46+
let n = {
47+
x: Math.round(12 * Math.random()),
48+
y: Math.round(5 * Math.random()),
49+
w: Math.round(1 + 3 * Math.random()),
50+
h: Math.round(1 + 3 * Math.random()),
51+
content: String(count++)
52+
};
53+
grid.addWidget(n);
54+
};
55+
56+
toggleFloat = function() {
57+
grid.float(! grid.getFloat());
58+
floatButton.innerHTML = 'float: ' + grid.getFloat();
59+
};
60+
floatButton.innerHTML = 'float: ' + grid.getFloat();
61+
62+
toggleMax = function() {
63+
grid.opts.maxRow = grid.engine.maxRow = grid.opts.maxRow ? 0 : 3;
64+
maxButton.innerHTML = 'Max: ' + grid.opts.maxRow;
65+
};
66+
maxButton.innerHTML = 'Max: ' + grid.opts.maxRow;
67+
68+
toggleBigger = function() {
69+
size = size === 1 ? 2 : 1;
70+
setSize(size);
71+
};
72+
setSize = function(size) {
73+
items.sort((a,b) => a.id - b.id);
74+
items.forEach((n,i) => {
75+
if (i<6) {
76+
n.w = n.h = size;
77+
n.y = i * size;
78+
if (n.x) n.x = size;
79+
} else {
80+
n.h = size;
81+
}
82+
});
83+
grid.opts.maxRow = grid.engine.maxRow = grid.opts.maxRow ? (size === 1 ? 3 : 6) : 0;
84+
grid.load(items);
85+
bigButton.innerHTML = 'Size: ' + size;
86+
maxButton.innerHTML = 'Max: ' + grid.opts.maxRow;
87+
}
88+
bigButton.innerHTML = 'Size: ' + size;
89+
if (size !== 1) setSize(size);
90+
</script>
91+
</body>
92+
</html>

spec/e2e/html/141_swap_old.html

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1">
7+
<title>old swap</title>
8+
9+
<link rel="stylesheet" href="../../../demo/demo.css"/>
10+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/gridstack@1.0.0/dist/gridstack.min.css"/>
11+
<script src="https://cdn.jsdelivr.net/npm/gridstack@1.0.0/dist/gridstack.all.js"></script>
12+
13+
</head>
14+
<body>
15+
<div class="container-fluid">
16+
<h1>Swap collision demo from older 1.x builds</h1>
17+
<div>
18+
<a class="btn btn-primary" onClick="addNewWidget()" href="#">Add Widget</a>
19+
<a class="btn btn-primary" onclick="toggleFloat()" id="float" href="#"></a>
20+
<a class="btn btn-primary" onclick="toggleMax()" id="max" href="#"></a>
21+
</div>
22+
<br><br>
23+
<div class="grid-stack">
24+
<div class="grid-stack-item" data-gs-x="0" data-gs-y="0"><div class="grid-stack-item-content">0</div></div>
25+
<div class="grid-stack-item" data-gs-x="0" data-gs-y="1"><div class="grid-stack-item-content">1</div></div>
26+
<div class="grid-stack-item" data-gs-x="0" data-gs-y="2"><div class="grid-stack-item-content">2</div></div>
27+
<div class="grid-stack-item" data-gs-x="1" data-gs-y="0"><div class="grid-stack-item-content">3</div></div>
28+
<div class="grid-stack-item" data-gs-x="1" data-gs-y="1"><div class="grid-stack-item-content">4</div></div>
29+
<div class="grid-stack-item" data-gs-x="1" data-gs-y="2"><div class="grid-stack-item-content">5</div></div>
30+
</div>
31+
</div>
32+
<script type="text/javascript">
33+
let floatButton = document.getElementById('float');
34+
let maxButton = document.getElementById('max');
35+
let count = 6;
36+
let grid = GridStack.init({float: false, cellHeight: 70, maxRow: 3});
37+
38+
addNewWidget = function() {
39+
let n = {
40+
x: Math.round(12 * Math.random()),
41+
y: Math.round(5 * Math.random()),
42+
w: Math.round(1 + 3 * Math.random()),
43+
h: Math.round(1 + 3 * Math.random()),
44+
content: String(count++)
45+
};
46+
grid.addWidget(n);
47+
};
48+
49+
toggleFloat = function() {
50+
grid.float(! grid.getFloat());
51+
floatButton.innerHTML = 'float: ' + grid.float();
52+
};
53+
floatButton.innerHTML = 'float: ' + grid.float();
54+
55+
toggleMax = function() {
56+
grid.opts.maxRow = grid.engine.maxRow = grid.opts.maxRow ? 0 : 3;
57+
maxButton.innerHTML = 'Max: ' + grid.opts.maxRow;
58+
};
59+
maxButton.innerHTML = 'Max: ' + grid.opts.maxRow;
60+
61+
</script>
62+
</body>
63+
</html>

spec/gridstack-engine-spec.ts

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ describe('gridstack engine', function() {
4545
describe('batch update', function() {
4646

4747
it('should set float and batchMode when calling batchUpdate.', function() {
48-
// Note: legacy weird call on global window to hold data
49-
e.prototype.batchUpdate.call(w);
50-
expect(w.float).toBe(undefined);
51-
expect(w.batchMode).toBeTrue();
48+
engine = new GridStackEngine({float: true});
49+
engine.batchUpdate();
50+
expect(engine.float).toBe(true);
51+
expect(engine.batchMode).toBeTrue();
5252
});
5353
});
5454

@@ -327,29 +327,29 @@ describe('gridstack engine', function() {
327327
});
328328
});
329329

330-
describe('test isNodeChangedPosition', function() {
330+
describe('test changedPos', function() {
331331
beforeAll(function() {
332332
engine = new GridStackEngine();
333333
});
334334
it('should return true for changed x', function() {
335335
let widget = { x: 1, y: 2, w: 3, h: 4 };
336-
expect(engine.isNodeChangedPosition(widget, 2, 2)).toEqual(true);
336+
expect(engine.changedPos(widget, 2, 2)).toEqual(true);
337337
});
338338
it('should return true for changed y', function() {
339339
let widget = { x: 1, y: 2, w: 3, h: 4 };
340-
expect(engine.isNodeChangedPosition(widget, 1, 1)).toEqual(true);
340+
expect(engine.changedPos(widget, 1, 1)).toEqual(true);
341341
});
342342
it('should return true for changed width', function() {
343343
let widget = { x: 1, y: 2, w: 3, h: 4 };
344-
expect(engine.isNodeChangedPosition(widget, 2, 2, 4, 4)).toEqual(true);
344+
expect(engine.changedPos(widget, 2, 2, 4, 4)).toEqual(true);
345345
});
346346
it('should return true for changed height', function() {
347347
let widget = { x: 1, y: 2, w: 3, h: 4 };
348-
expect(engine.isNodeChangedPosition(widget, 1, 2, 3, 3)).toEqual(true);
348+
expect(engine.changedPos(widget, 1, 2, 3, 3)).toEqual(true);
349349
});
350350
it('should return false for unchanged position', function() {
351351
let widget = { x: 1, y: 2, w: 3, h: 4 };
352-
expect(engine.isNodeChangedPosition(widget, 1, 2, 3, 4)).toEqual(false);
352+
expect(engine.changedPos(widget, 1, 2, 3, 4)).toEqual(false);
353353
});
354354
});
355355

@@ -371,13 +371,15 @@ describe('gridstack engine', function() {
371371
expect(findNode(engine, 2)).toEqual(jasmine.objectContaining({x: 1, y: 2}));
372372
// prevents moving locked item
373373
let node1 = findNode(engine, 1);
374-
expect(engine.moveNode(node1, 6, 6)).toEqual(null);
374+
expect(engine.moveNode(node1, 6, 6)).toEqual(false);
375375
// but moves regular one (gravity ON)
376376
let node2 = findNode(engine, 2);
377-
expect(engine.moveNode(node2, 6, 6)).toEqual(jasmine.objectContaining({x: 6, y: 2, w: 2, h: 3,}));
377+
expect(engine.moveNode(node2, 6, 6)).toEqual(true);
378+
expect(node2).toEqual(jasmine.objectContaining({x: 6, y: 2, w: 2, h: 3}));
378379
// but moves regular one (gravity OFF)
379380
engine.float = true;
380-
expect(engine.moveNode(node2, 7, 6)).toEqual(jasmine.objectContaining({x: 7, y: 6, w: 2, h: 3,}));
381+
expect(engine.moveNode(node2, 7, 6)).toEqual(true);
382+
expect(node2).toEqual(jasmine.objectContaining({x: 7, y: 6, w: 2, h: 3}));
381383
});
382384
});
383385

0 commit comments

Comments
 (0)