Skip to content

Commit

Permalink
feat(Layout): add LightBoxLayout
Browse files Browse the repository at this point in the history
  • Loading branch information
daybrush committed Oct 12, 2017
1 parent f477a04 commit 4ac2ab8
Show file tree
Hide file tree
Showing 3 changed files with 246 additions and 1 deletion.
3 changes: 2 additions & 1 deletion config/webpack.config.layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ var config = {
entry: {
"JustifiedLayout": "./src/layouts/JustifiedLayout.js",
"GridLayout": "./src/layouts/GridLayout.js",
"FrameLayout": "./src/layouts/FrameLayout.js"
"FrameLayout": "./src/layouts/FrameLayout.js",
"LightBoxLayout": "./src/layouts/LightBoxLayout.js"
},
output: {
path: path.resolve(__dirname, "../dist"),
Expand Down
146 changes: 146 additions & 0 deletions src/layouts/LightBoxLayout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import {APPEND, PREPEND, HORIZONTAL} from "./Constants";
import {getStyleNames, assignOptions} from "./utils";

function fill(length, pos) {
return new Array(length).fill(pos);
}

class LightBoxLayout {
constructor(options = {}) {
this._options = assignOptions({
tolerance: 1,
}, options);
this._viewport = {};
this._isHorizontal = this._options.direction === HORIZONTAL;
this._columnSize = 0;
this._columnLength = 0;
this._style = getStyleNames(this._options.direction);
}
checkColumn(item) {
const margin = this._options.margin;
// if direction is horizontal, fixed dimension is height
// if direction is vertical, fixed dimension is width
const sizeName = this._style.size2;
const columnSize = item.size[sizeName];
const columnLength = parseInt((this._viewport[sizeName] + margin) / (columnSize + margin), 10);

this._columnLength = Math.max(columnLength, 1);
this._columnSize = columnSize;
}
_layout(items, outline, isAppend) {
const length = items.length;
const margin = this._options.margin;
const tolerance = this._options.tolerance || 1;
const style = this._style;
const size1Name = style.size1;
const size2Name = style.size2;
const pos1Name = style.pos1;
const pos2Name = style.pos2;
const columnSize = this._columnSize;
const pointCaculateName = isAppend ? "min" : "max";
const startOutline = outline.slice();
const endOutline = outline.slice();
const columnLength = this._columnLength;

for (let i = 0; i < length; ++i) {
const point = Math[pointCaculateName](...endOutline);
const index = endOutline.indexOf(point);
const item = items[isAppend ? i : length - 1 - i];
const originalSize1 = item.size[size1Name];
const originalSize2 = item.size[size2Name];
const pos2 = (columnSize + margin) * index;
let size1 = originalSize1;
let size2 = originalSize2;
let columnCount = 1;

if (item.column > 1) {
// 1(min) <= real column count <= item.column(max)
for (let j = 1; j < item.column && index + j < columnLength; ++j) {
if ((isAppend && endOutline[index + j] <= point) ||
(!isAppend && endOutline[index + j] >= point)) {
++columnCount;
continue;
}
break;
}
// resize according to column count
size2 = (columnSize + margin) * columnCount - margin;
size1 = size2 * originalSize1 / originalSize2;
}
size1 -= (point < 0 ? (-point + margin + size1) : (point + size1)) % tolerance;
const pos1 = isAppend ? point : point - margin - size1;
const endPos1 = pos1 + size1 + margin;

// tetris
item.rect = {
[pos1Name]: pos1,
[pos2Name]: pos2,
[size1Name]: size1,
[size2Name]: size2,
};
for (let j = 0; j < columnCount; ++j) {
endOutline[index + j] = isAppend ? endPos1 : pos1;
}
}
// if append items, startOutline is low, endOutline is high
// if prepend items, startOutline is high, endOutline is low
return {
start: isAppend ? startOutline : endOutline,
end: isAppend ? endOutline : startOutline,
};
}
_insert(items, outline, type) {
const clone = items.map(item => Object.assign({}, item));

let startOutline = outline;

if (!this._columnLength) {
this.checkColumn(items[0]);
}
if (outline.length !== this._columnLength) {
startOutline = fill(this._columnLength, Math[type === APPEND ? "min" : "max"](...outline));
}

const result = this._layout(clone, startOutline, type);

return {
items: clone,
outlines: result,
};
}
append(items, outline) {
return this._insert(items, outline, APPEND);
}
prepend(items, outline) {
return this._insert(items, outline, PREPEND);
}
layout(groups, outline) {
this.checkColumn(groups[0].items[0]);
// if outlines' length and columns' length are now same, re-caculate outlines.
let startOutline;

if (outline.length !== this._columnLength) {
const pos = Math.min(...outline);

// re-layout items.
startOutline = fill(this._columnLength, pos);
} else {
startOutline = outline.slice();
}
groups.forEach(group => {
const items = group.items;
const result = this._layout(items, startOutline, APPEND);

group.outlines = result;
startOutline = result.end;
});
}
setViewport(width, height) {
const viewport = this._viewport;

viewport.width = width;
viewport.height = height;
}
}

export default LightBoxLayout;
98 changes: 98 additions & 0 deletions test/manual/layouts/LightBoxLayout.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=Edge">
<title>InfiniteGrid: demo</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no, target-densitydpi=medium-dpi">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/css/bootstrap.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootflat/2.0.4/css/bootflat.css">
<link rel="stylesheet" href="../../../demo/assets/css/demo.css">
<link rel="stylesheet" href="./demo.css">
<!--[if lt IE 9]>
<script src="https://cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.js"></script>
<![endif]-->
</head>
<body>
<div class="container">
<!-- navbar -->
<div class="row">
<div class="col-md-12">
<nav class="navbar navbar-inverse" role="navigation">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#">egjs infiniteGrid</a>
</div>
</div>
</nav>
</div>
</div>
<!-- infinite grid -->
<div id="grid" class="row"></div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.5.9/es5-shim.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/es5-shim/4.5.9/es5-sham.js"></script>
<script src="../../../node_modules/jquery/dist/jquery.js"></script>
<!-- <script src="../../node_modules/@egjs/component/dist/component.js"></script> -->
<script src="../../../dist/infinitegrid.pkgd.js"></script>
<script src="../../../dist/LightBoxLayout.js"></script>
<script src="../../../lib/Render.js"></script>
<script src="./js/demo.js"></script>
<style>
#grid.row {
height: 1000px;
position: relative;
}
.item {
position: absolute;
overflow: hidden;
background-color: #fff;
border: 1px solid #ddd;
border-radius: 4px;
-webkit-transition: border .2s ease-in-out;
-o-transition: border .2s ease-in-out;
transition: border .2s ease-in-out;
box-shadow: 0 1px 2px rgba(0, 0, 0, .2);
padding: 4px;
}
.item .thumbnail {
background: transparent;
border: none;
border-radius: 0;
box-shadow: none;
padding: 0;
}
</style>
<script>
var a = new LightBoxLayout({
direction: "vertical",
margin: 20,
tolerance: 100,
});
a._viewport.width = document.querySelector("#grid").offsetWidth;
a._viewport.height = document.querySelector("#grid").offsetHeight;
const _getItems = getItems;
getItems = function(num) {
const items = _getItems(num);

items[0].column = 2;
items[1].column = 3;
if (items.length > 11) {
items[11].column = 2;
}
return items;
}
function getWidth() {
return 200;
}
function getHeight() {
return parseInt(Math.random() * 200, 10) + 100;
}

append([600], 9);
append(undefined, 12);
prepend(undefined, 7);
</script>
</body>
</html>

0 comments on commit 4ac2ab8

Please sign in to comment.