Permalink
Browse files

Magic Grid for dynamic grid layouts

  • Loading branch information...
e-oj committed Nov 12, 2018
0 parents commit fed0e0a180fa9cd857c9f91297462f9995aa4d9f
Showing with 5,509 additions and 0 deletions.
  1. +5 −0 .babelrc
  2. +3 −0 .gitignore
  3. +5,109 −0 package-lock.json
  4. +42 −0 package.json
  5. +198 −0 src/index.js
  6. +61 −0 src/utils.js
  7. +59 −0 test/grid.html
  8. +32 −0 webpack.config.js
@@ -0,0 +1,5 @@
{
"presets": [
["@babel/preset-env", {"modules": false}]
]
}
@@ -0,0 +1,3 @@
.idea

node_modules

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -0,0 +1,42 @@
{
"name": "magic-grid",
"version": "0.0.0",
"description": "Super lightweight javascript library for dynamic grid layouts.",
"main": "dist/magic-grid.min.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"make": "cross-env webpack --mode=none --progress --hide-modules",
"make-min": "MIN=yes cross-env webpack --mode=none --progress --hide-modules",
"build": "npm run make && npm run make-min"
},
"repository": {
"type": "git",
"url": "git+https://github.com/e-oj/Magic-Grid.git"
},
"keywords": [
"js",
"grid",
"javascript",
"grid",
"grid",
"grid",
"layout"
],
"author": "Emmanuel Olaojo",
"license": "MIT",
"bugs": {
"url": "https://github.com/e-oj/Magic-Grid/issues"
},
"homepage": "https://github.com/e-oj/Magic-Grid#readme",
"devDependencies": {
"@babel/core": "^7.1.5",
"@babel/preset-env": "^7.1.5",
"babel-loader": "^8.0.4",
"cross-env": "^5.2.0",
"webpack": "^4.25.1",
"webpack-cli": "^3.1.2"
},
"dependencies": {
"jquery": "^3.3.1"
}
}
@@ -0,0 +1,198 @@
/**
* @author emmanuelolaojo
* @since 11/10/18
*
* The MagicGrid class is an
* implementation of a flexible
* grid layout.
*/

import jquery from "jquery";
import {getMax, checkParams, getMin} from "./utils"

export default class MagicGrid {
/**
* Initializes the necessary variables
* for a magic grid.
*
* @param config - configuration object
*/
constructor(config){
checkParams(config);

this.$ = jquery;
this.containerClass = config.container;
this.container = this.$(config.container);
this.item = this.container.children();
this.size = config.items;
this.gutter = config.gutter || 25;
this.maxColumns = config.maxColumns || false;
this.useMin = config.useMin || false;
this.animate = config.animate || false;
this.static = config.static || false;
this.started = false;

this._init();
}

/**
* Initializes styles
*
* @private
*/
_init(){
if(!this.ready() || this.started) return;

this.container.css({position: "relative"});
this.item.css({position: "absolute"});

if(this.animate){
this.item.css({transition: "top,left 0.2s ease"});
}

this.started = true;
}

/**
* Calculates the width of a column.
*
* @return width of a column in the grid
* @private
*/
_colWidth(){
return this.item.outerWidth() + this.gutter;
}

/**
* Initializes an array of empty columns
* and calculates the leftover whitespace.
*
* @return {{cols: Array, wSpace: number}}
* @private
*/
_setup(){
let width = this.container.outerWidth();
let numCols = Math.floor(width/this._colWidth()) || 1;
let cols = [];

if(this.maxColumns && numCols > this.maxColumns){
numCols = this.maxColumns;
}

for(let i = 0; i < numCols; i++){
cols[i] = {height: 0, top: 0, index: i}
}

let wSpace = width - numCols * this._colWidth() + this.gutter;

return {cols, wSpace};
}

/**
* Gets the next available column.
*
* @param cols list of columns
* @param i index of dom element
*
* @return {*} next available column
* @private
*/
_nextCol(cols, i){
if(this.useMin){
return getMin(cols);
}

return cols[i % cols.length];
}

/**
* Position each item in the container
* based on their corresponding columns
* values.
*/
positionItems(){
let self = this;
let {cols, wSpace} = this._setup();

console.log(wSpace);
wSpace = Math.floor(wSpace/2);
console.log(wSpace);

self.item.each(function(i){
let min = self._nextCol(cols, i);
let left = min.index * self._colWidth() + wSpace;
let $item = self.$(this);

$item.css({
left: left + "px",
top: min.height + min.top + "px"
});

min.height += min.top + $item.outerHeight();
min.top = self.gutter;
});

self.container.css({
height: getMax(cols).height,
});
}

/**
* Checks if every item has been loaded
* in the dom.
*
* @return {Boolean} true if every item is present
*/
ready(){
if(this.static) return true;
return this.container.length > 0 && this.item.length === this.size;
}

/**
* Periodically checks that all items
* have been loaded in the dom. Calls
* this.listen() once all the items are
* present.
*
* @private
*/
_getReady(){
let self = this;

let interval = setInterval(function(){
self.container = self.$(self.containerClass);
self.item = self.container.children();

console.log(self.container.children());

if(self.ready()){
clearInterval(interval);

self._init();
self.listen();
}

}, 100);
}

/**
* Positions all the items and
* repositions them whenever the
* window size changes.
*/
listen(){
let self = this;

if(self.ready()){
self.positionItems();

self.$(window).resize(function(){
setTimeout(function(){
self.positionItems();
}, 200);
});
}

else self._getReady();
}
}
@@ -0,0 +1,61 @@
/**
* @author emmanuelolaojo
* @since 11/11/18
*/

export {checkParams, getMax, getMin}

/**
* Validates the configuration object.
*
* @param config - configuration object
*/
function checkParams(config){
if(!config.container) error("container");
if(!config.items && !config.static) error("items or static")
}


function error(prop){
throw new Error(`Missing property '${prop}' in MagicGrid config`);
}

/**
* Finds the longest column in
* a column list
*
* @param cols - list of columns
*
* @return longest column
*/
function getMax(cols){
let max = cols[0];

for(let col of cols){
if(col.height > max.height){
max = col
}
}

return max;
}

/**
* Finds the longest column in
* a column list
*
* @param cols - list of columns
*
* @return longest column
*/
function getMin(cols){
let min = cols[0];

for(let col of cols){
if(col.height < min.height){
min = col
}
}

return min;
}
@@ -0,0 +1,59 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Magic Grid</title>
</head>
<body>
<div id="container">
<div class="item1"></div>
<div class="item2"></div>
<div class="item3"></div>
<div class="item4"></div>
<div class="item5"></div>
<div class="item6"></div>
<div class="item7"></div>
<div class="item8"></div>
<div class="item9"></div>
<div class="item10"></div>
<div class="item11"></div>
<div class="item12"></div>
<div class="item13"></div>
</div>

<style>
#container div{
width: 200px;
height: 500px;
background-color: antiquewhite;
}
#container .item1{
height: 200px;
}
#container .item4{
height: 800px;
}
#container .item11{
height: 400px;
}
</style>

<script src="../dist/magic-grid.js"></script>
<script>
console.log(MagicGrid);
let magicGrid = new MagicGrid({
container: "#container",
animate: true,
gutter: 30,
useMin: true,
static: true
});
magicGrid.listen();
</script>
</body>
</html>
Oops, something went wrong.

0 comments on commit fed0e0a

Please sign in to comment.