Skip to content

Commit

Permalink
Merge pull request #1621 from adumesny/develop
Browse files Browse the repository at this point in the history
collision overall - support for swap
  • Loading branch information
adumesny authored Feb 15, 2021
2 parents 98aa68e + 270dde4 commit 6d122cd
Show file tree
Hide file tree
Showing 9 changed files with 433 additions and 243 deletions.
3 changes: 3 additions & 0 deletions doc/CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ Change log
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## 3.3.0-dev

- 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>
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>
Still TODO: handle mid point of dragged over items rather 50% of row/column and check for the most covered when multiple items collide.
- fix [1617](https://github.com/gridstack/gridstack.js/issues/1617) FireFox DOM order issue. Thanks [@marcel-necker](https://github.com/marcel-necker)

## 3.3.0 (2021-2-2)
Expand Down
92 changes: 92 additions & 0 deletions spec/e2e/html/141_1534_swap.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>swap demo</title>

<link rel="stylesheet" href="../../../demo/demo.css"/>
<script src="../../../dist/gridstack-h5.js"></script>

</head>
<body>
<div class="container-fluid">
<h1>Swap collision demo</h1>
<div>
<a class="btn btn-primary" onClick="addNewWidget()" href="#">Add Widget</a>
<a class="btn btn-primary" onclick="toggleFloat()" id="float" href="#"></a>
<a class="btn btn-primary" onclick="toggleMax()" id="max" href="#"></a>
<a class="btn btn-primary" onclick="toggleBigger()" id="big" href="#"></a>
</div>
<br><br>
<div class="grid-stack"></div>
</div>
<script src="../../../demo/events.js"></script>
<script type="text/javascript">
let floatButton = document.getElementById('float');
let maxButton = document.getElementById('max');
let bigButton = document.getElementById('big');
let size = 1;

let grid = GridStack.init({float: false, cellHeight: 70, maxRow: 0});
addEvents(grid);

let count = 0;
let items = [
{x:0, y:0}, {x:0, y:1}, {x:0, y:2},{x:1, y:0}, {x:1, y:1}, {x:1, y:2},
{x:5, y:0}, {x:4, y:1, w:3, locked: false, _content: 'locked'}, {x:5, y:2},
{x:7, y:0}, {x:8, y:0}, {x:9, y:0}, {x:7, y:1, w:3}, {x:8, y:2},
{x:11, y:0}, {x:11, y:1, h:2},
];
items.forEach(n => {n.id = count; n.content = n.content || String(count); count++})
grid.load(items);

addNewWidget = function() {
let n = {
x: Math.round(12 * Math.random()),
y: Math.round(5 * Math.random()),
w: Math.round(1 + 3 * Math.random()),
h: Math.round(1 + 3 * Math.random()),
content: String(count++)
};
grid.addWidget(n);
};

toggleFloat = function() {
grid.float(! grid.getFloat());
floatButton.innerHTML = 'float: ' + grid.getFloat();
};
floatButton.innerHTML = 'float: ' + grid.getFloat();

toggleMax = function() {
grid.opts.maxRow = grid.engine.maxRow = grid.opts.maxRow ? 0 : 3;
maxButton.innerHTML = 'Max: ' + grid.opts.maxRow;
};
maxButton.innerHTML = 'Max: ' + grid.opts.maxRow;

toggleBigger = function() {
size = size === 1 ? 2 : 1;
setSize(size);
};
setSize = function(size) {
items.sort((a,b) => a.id - b.id);
items.forEach((n,i) => {
if (i<6) {
n.w = n.h = size;
n.y = i * size;
if (n.x) n.x = size;
} else {
n.h = size;
}
});
grid.opts.maxRow = grid.engine.maxRow = grid.opts.maxRow ? (size === 1 ? 3 : 6) : 0;
grid.load(items);
bigButton.innerHTML = 'Size: ' + size;
maxButton.innerHTML = 'Max: ' + grid.opts.maxRow;
}
bigButton.innerHTML = 'Size: ' + size;
if (size !== 1) setSize(size);
</script>
</body>
</html>
63 changes: 63 additions & 0 deletions spec/e2e/html/141_swap_old.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>old swap</title>

<link rel="stylesheet" href="../../../demo/demo.css"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/gridstack.min.css"/>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/gridstack.all.js"></script>

</head>
<body>
<div class="container-fluid">
<h1>Swap collision demo from older 1.x builds</h1>
<div>
<a class="btn btn-primary" onClick="addNewWidget()" href="#">Add Widget</a>
<a class="btn btn-primary" onclick="toggleFloat()" id="float" href="#"></a>
<a class="btn btn-primary" onclick="toggleMax()" id="max" href="#"></a>
</div>
<br><br>
<div class="grid-stack">
<div class="grid-stack-item" data-gs-x="0" data-gs-y="0"><div class="grid-stack-item-content">0</div></div>
<div class="grid-stack-item" data-gs-x="0" data-gs-y="1"><div class="grid-stack-item-content">1</div></div>
<div class="grid-stack-item" data-gs-x="0" data-gs-y="2"><div class="grid-stack-item-content">2</div></div>
<div class="grid-stack-item" data-gs-x="1" data-gs-y="0"><div class="grid-stack-item-content">3</div></div>
<div class="grid-stack-item" data-gs-x="1" data-gs-y="1"><div class="grid-stack-item-content">4</div></div>
<div class="grid-stack-item" data-gs-x="1" data-gs-y="2"><div class="grid-stack-item-content">5</div></div>
</div>
</div>
<script type="text/javascript">
let floatButton = document.getElementById('float');
let maxButton = document.getElementById('max');
let count = 6;
let grid = GridStack.init({float: false, cellHeight: 70, maxRow: 3});

addNewWidget = function() {
let n = {
x: Math.round(12 * Math.random()),
y: Math.round(5 * Math.random()),
w: Math.round(1 + 3 * Math.random()),
h: Math.round(1 + 3 * Math.random()),
content: String(count++)
};
grid.addWidget(n);
};

toggleFloat = function() {
grid.float(! grid.getFloat());
floatButton.innerHTML = 'float: ' + grid.float();
};
floatButton.innerHTML = 'float: ' + grid.float();

toggleMax = function() {
grid.opts.maxRow = grid.engine.maxRow = grid.opts.maxRow ? 0 : 3;
maxButton.innerHTML = 'Max: ' + grid.opts.maxRow;
};
maxButton.innerHTML = 'Max: ' + grid.opts.maxRow;

</script>
</body>
</html>
28 changes: 15 additions & 13 deletions spec/gridstack-engine-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ describe('gridstack engine', function() {
describe('batch update', function() {

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

Expand Down Expand Up @@ -327,29 +327,29 @@ describe('gridstack engine', function() {
});
});

describe('test isNodeChangedPosition', function() {
describe('test changedPos', function() {
beforeAll(function() {
engine = new GridStackEngine();
});
it('should return true for changed x', function() {
let widget = { x: 1, y: 2, w: 3, h: 4 };
expect(engine.isNodeChangedPosition(widget, 2, 2)).toEqual(true);
expect(engine.changedPos(widget, 2, 2)).toEqual(true);
});
it('should return true for changed y', function() {
let widget = { x: 1, y: 2, w: 3, h: 4 };
expect(engine.isNodeChangedPosition(widget, 1, 1)).toEqual(true);
expect(engine.changedPos(widget, 1, 1)).toEqual(true);
});
it('should return true for changed width', function() {
let widget = { x: 1, y: 2, w: 3, h: 4 };
expect(engine.isNodeChangedPosition(widget, 2, 2, 4, 4)).toEqual(true);
expect(engine.changedPos(widget, 2, 2, 4, 4)).toEqual(true);
});
it('should return true for changed height', function() {
let widget = { x: 1, y: 2, w: 3, h: 4 };
expect(engine.isNodeChangedPosition(widget, 1, 2, 3, 3)).toEqual(true);
expect(engine.changedPos(widget, 1, 2, 3, 3)).toEqual(true);
});
it('should return false for unchanged position', function() {
let widget = { x: 1, y: 2, w: 3, h: 4 };
expect(engine.isNodeChangedPosition(widget, 1, 2, 3, 4)).toEqual(false);
expect(engine.changedPos(widget, 1, 2, 3, 4)).toEqual(false);
});
});

Expand All @@ -371,13 +371,15 @@ describe('gridstack engine', function() {
expect(findNode(engine, 2)).toEqual(jasmine.objectContaining({x: 1, y: 2}));
// prevents moving locked item
let node1 = findNode(engine, 1);
expect(engine.moveNode(node1, 6, 6)).toEqual(null);
expect(engine.moveNode(node1, 6, 6)).toEqual(false);
// but moves regular one (gravity ON)
let node2 = findNode(engine, 2);
expect(engine.moveNode(node2, 6, 6)).toEqual(jasmine.objectContaining({x: 6, y: 2, w: 2, h: 3,}));
expect(engine.moveNode(node2, 6, 6)).toEqual(true);
expect(node2).toEqual(jasmine.objectContaining({x: 6, y: 2, w: 2, h: 3}));
// but moves regular one (gravity OFF)
engine.float = true;
expect(engine.moveNode(node2, 7, 6)).toEqual(jasmine.objectContaining({x: 7, y: 6, w: 2, h: 3,}));
expect(engine.moveNode(node2, 7, 6)).toEqual(true);
expect(node2).toEqual(jasmine.objectContaining({x: 7, y: 6, w: 2, h: 3}));
});
});

Expand Down
Loading

0 comments on commit 6d122cd

Please sign in to comment.