├── README.md ├── css └── style.css ├── index.html └── js ├── exampleUsage.js ├── smartContentPlacer.js └── smartContentPlacer_min.js /README.md: -------------------------------------------------------------------------------- 1 | Smart-Content-Placer 2 | ==================== 3 | 4 | A small JavaScript class to programmatically position difficult content. What do I mean by that? Well lets assume you have many images which are different widths and heights. How do you place them on a page such that there are no "gaps"? This is basically a constrained bin packing problem. Using just CSS this is a no go as you will end up with blocks of whitespace appearing, thus some JavaScript is required. This little component allows for variable width and height content - imagine Pinterest on steroids (Pinterest only allows for variable height). 5 | 6 | ## Live Demo 7 | 8 | Please read comments in JavaScript for examples on how to use. 9 | 10 | A live demo is available on my website - resize the window to see how it adapts: 11 | http://jasonmayes.com/projects/contentPlacer/ 12 | 13 | ![Browser Support](https://lh4.googleusercontent.com/-nY3uAwOz_x4/U8TqKTSXCWI/AAAAAAAAaL4/YI6Pm8EHb1Y/w600-h384-no/ContentPlacer_jasonMayes.gif "Browser Support") 14 | 15 | ## Key features 16 | 17 | * Fully responsive (up to the largest element width used). 18 | * Allows for variable width AND height content. All content must be a multiple of a base unit size. 19 | * Works with any type of responsive content (not just images). 20 | * Supports margins between content. 21 | * Works in all modern browsers. 22 | * Supports transitions for initial display and for fluid repositioning of content. 23 | * Requires no 3rd party libraries to work - pure native JavaScript. 24 | * Lightweight and efficient. 25 | * Fully customizable - all transitions / style is defined via CSS. 26 | 27 | ## Why does this exist? 28 | 29 | After a quick Google it seemed many other existing solutions required some third party library to work (jQuery), or were not as efficient as I wanted. I therefore decided to roll my own from a blank canvas to keep it as lightweight and efficient as possible. 30 | 31 | ## Browser support 32 | 33 | All popular browsers supported. Chrome, Firefox, Safari, Opera, Internet Explorer 9+ and I have tested on Android/iOS which seems to be fine too. 34 | ![Browser Support](http://jasonmayes.com/projects/twitterApi/browsers.jpg "Browser Support") 35 | 36 | ## Got suggestions? Feedback? Feature requests? Tell me! 37 | 38 | Really, I like to hear feedback, and love to see what projects you have used it in. Feel free to give me a shoutout if you have used it. 39 | Talk to me: Via [Google+](https://plus.google.com/110804953626559077511/posts/iPbbwX7ivqW), [twitter](http://www.twitter.com/jason_mayes), or my [website](http://www.jasonmayes.com/). 40 | 41 | ## Terms 42 | 43 | Feel free to use in your own personal projects. I only ask you keep any disclaimers with my code (even if code is modified / minified) so others can find the original source should they wish to get updates or support. A link back / social media shout out is always appreciated to help others discover it (and for me to see what great things it is being used for) but not required :-) 44 | 45 | If you plan to use in a commercial project please contact me first if you are unable to adhere to the above terms. 46 | -------------------------------------------------------------------------------- /css/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | * General Styles - not component critical but used to achieve demo 3 | * look and feel. 4 | */ 5 | 6 | html, body { 7 | margin:0; 8 | } 9 | 10 | body { 11 | font-family:Arial,"Liberation Sans",sans-serif; 12 | } 13 | 14 | h1, p { 15 | margin:25px; 16 | color:#3d3d3d; 17 | margin-bottom:10px; 18 | } 19 | 20 | p { 21 | color:#7d7d7d; 22 | padding-right:100px; 23 | float:left; 24 | margin:0 25px 25px 25px; 25 | font-size:10pt; 26 | } 27 | 28 | #intro1, #intro2, #intro3 { 29 | font-size:12pt; 30 | } 31 | 32 | #linkage { 33 | position:fixed; 34 | top:70px; 35 | right:0px; 36 | background-color:#2d2d3d; 37 | color:#ffffff; 38 | text-decoration:none; 39 | padding:10px; 40 | width:100px; 41 | z-index:2; 42 | } 43 | 44 | #listView { 45 | width:100%; 46 | min-width:150px; 47 | clear:both; 48 | } 49 | 50 | .container { 51 | margin:25px; 52 | } 53 | 54 | .hide { 55 | display:none; 56 | } 57 | 58 | .contentPlacerContainer .bar { 59 | position:absolute; 60 | bottom:0; 61 | height:50px; 62 | background-color:rgba(30,30,30, 0.8); 63 | width:100%; 64 | color:#ffffff; 65 | } 66 | 67 | .contentPlacerContainer h2 { 68 | margin:6px 15px 0 10px; 69 | font-size:10pt; 70 | } 71 | 72 | .contentPlacerContainer p { 73 | color:#dfdfdf; 74 | margin:5px 15px 0 10px; 75 | font-size:10pt; 76 | float:none; 77 | padding:0; 78 | } 79 | 80 | .contentPlacerContainer .content { 81 | width:100%; 82 | height:100%; 83 | overflow:hidden; 84 | background-repeat:no-repeat; 85 | background-size:cover; 86 | display:block; 87 | position:relative; 88 | } 89 | 90 | 91 | /* 92 | * Component Critical Styles - you must include these! 93 | * Dont change unless you know what you are doing. 94 | */ 95 | 96 | .contentPlacerContainer { 97 | position:relative; 98 | margin:0; 99 | padding:0; 100 | } 101 | 102 | .contentPlacerContainer .contentPlacerElement { 103 | position:absolute; 104 | overflow:hidden; 105 | opacity:1; 106 | background-color:transparent; 107 | } 108 | 109 | .contentPlacerElement.hidden { 110 | opacity:0; 111 | -ms-Transform:scale(0, 0); 112 | -webkit-Transform: scale(0, 0); 113 | transform: scale(0, 0); 114 | } 115 | 116 | .contentPlacerContainer .transition { 117 | -webkit-transition: all 500ms ease-in-out; 118 | -moz-transition: all 500ms ease-in-out; 119 | -o-transition: all 500ms ease-in-out; 120 | transition: all 500ms ease-in-out; 121 | } 122 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Smart Content Placer by Jason Mayes 9 | 10 | 11 | 12 |

Smart Content / Image Placer

13 |

5 seconds after this page loads we shall change the margin to 1px and the base unit size to 200px.

14 |

In another 5 seconds we shall simulate updating the component with new data (e.g. from some API) and change the draw speed.

15 |

Cool huh? Now resize this page!

16 |

I have created a small component to programmatically position difficult content. What do I mean by that? Well lets assume you have many images which are different widths and heights. How do you fit them on a page such that there are no "gaps"? Using just CSS this is a no go. Imagine Pinterest on steroids Pinterest only allows for variable height), this little component allows for variable width and height content! Enjoy :-) Give me a shoutout if you use it, would love to see!

17 | View my website 18 | 19 |
20 |
21 |
22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /js/exampleUsage.js: -------------------------------------------------------------------------------- 1 | // *********************************************************************** 2 | // Example usage... Please note how the content is responsive to fill it's 3 | // Container - eg in this case we set image width to 100%. Content must be 4 | // responsive because if margins are used the image must be stretched ever 5 | // so slightly to compensate for margins. If you do not have responsive 6 | // data you will end up with a double margin gap on larger sized data. 7 | // *********************************************************************** 8 | 9 | // To make things easier to read I have made a little class to hold data 10 | // attributes. You could just use a JSON object with the same properties exposed 11 | // if you desired. 12 | var ContentPlacerData = function(content, unitWidth, unitHeight) { 13 | this.content = content; 14 | this.height = unitHeight; 15 | this.width = unitWidth; 16 | }; 17 | 18 | var dataArrayExample = []; 19 | dataArrayExample.push(new ContentPlacerData('

Its a kitten!

Meow nom nom

', 1 ,1)); 20 | dataArrayExample.push(new ContentPlacerData('

Wide kitten is wide

I can haz fish pls?

', 2 ,1)); 21 | dataArrayExample.push(new ContentPlacerData('

Its a kitten!

Meow nom nom

', 1 ,1)); 22 | dataArrayExample.push(new ContentPlacerData('

Its a kitten!

Meow nom nom

', 1 ,1)); 23 | dataArrayExample.push(new ContentPlacerData('

Double width and height cat

Do I look fat? Its my furs.

', 2 ,2)); 24 | dataArrayExample.push(new ContentPlacerData('

Its a kitten!

Meow nom nom

', 1 ,1)); 25 | dataArrayExample.push(new ContentPlacerData('

Its a kitten!

Meow nom nom

', 1 ,1)); 26 | dataArrayExample.push(new ContentPlacerData('

Wide kitten is wide

I can haz fish pls?

', 2 ,1)); 27 | dataArrayExample.push(new ContentPlacerData('

Its a kitten!

Meow nom nom

', 1 ,1)); 28 | dataArrayExample.push(new ContentPlacerData('

Its a kitten!

Meow nom nom

', 1 ,1)); 29 | dataArrayExample.push(new ContentPlacerData('

Its a kitten!

Meow nom nom

', 1 ,1)); 30 | dataArrayExample.push(new ContentPlacerData('

Its a kitten!

Meow nom nom

', 1 ,1)); 31 | dataArrayExample.push(new ContentPlacerData('

Double width and height cat

Do I look fat? Its my furs.

', 2 ,2)); 32 | dataArrayExample.push(new ContentPlacerData('

Its a kitten!

Meow nom nom

', 1 ,1)); 33 | dataArrayExample.push(new ContentPlacerData('

Its a kitten!

Meow nom nom

', 1 ,1)); 34 | dataArrayExample.push(new ContentPlacerData('

Wide kitten is wide

I can haz fish pls?

', 2 ,1)); 35 | dataArrayExample.push(new ContentPlacerData('

Its a kitten!

Meow nom nom

', 1 ,1)); 36 | dataArrayExample.push(new ContentPlacerData('

Its a kitten!

Meow nom nom

', 1 ,1)); 37 | dataArrayExample.push(new ContentPlacerData('

Its a kitten!

Meow nom nom

', 1 ,1)); 38 | dataArrayExample.push(new ContentPlacerData('

Its a kitten!

Meow nom nom

', 1 ,1)); 39 | dataArrayExample.push(new ContentPlacerData('

Its a kitten!

Meow nom nom

', 2 ,2)); 40 | dataArrayExample.push(new ContentPlacerData('

Its a kitten!

Meow nom nom

', 1 ,1)); 41 | dataArrayExample.push(new ContentPlacerData('

Wide kitten is wide

I can haz fish pls?

', 2 ,1)); 42 | dataArrayExample.push(new ContentPlacerData('

Its a kitten!

Meow nom nom

', 1 ,1)); 43 | dataArrayExample.push(new ContentPlacerData('

Its a kitten!

Meow nom nom

', 1 ,1)); 44 | dataArrayExample.push(new ContentPlacerData('

Double width and height cat

Do I look fat? Its my furs.

', 2 ,2)); 45 | dataArrayExample.push(new ContentPlacerData('

Its a kitten!

Meow nom nom

', 1 ,1)); 46 | dataArrayExample.push(new ContentPlacerData('

Its a kitten!

Meow nom nom

', 1 ,1)); 47 | dataArrayExample.push(new ContentPlacerData('

Wide kitten is wide

I can haz fish pls?

', 2 ,1)); 48 | dataArrayExample.push(new ContentPlacerData('

Its a kitten!

Meow nom nom

', 1 ,1)); 49 | dataArrayExample.push(new ContentPlacerData('

Its a kitten!

Meow nom nom

', 1 ,1)); 50 | dataArrayExample.push(new ContentPlacerData('

Its a kitten!

Meow nom nom

', 1 ,1)); 51 | dataArrayExample.push(new ContentPlacerData('

Its a kitten!

Meow nom nom

', 1 ,1)); 52 | 53 | // Create new instance and use the above data. 54 | var myPlacer = new ContentPlacer('listView', 250, 4, dataArrayExample, 30); 55 | 56 | // After 5 seconds, change margin and size of units and see it update live! 57 | setTimeout(function() { 58 | document.getElementById('intro1').className = 'hide'; 59 | document.getElementById('intro2').className = ''; 60 | myPlacer.setMargin(1); 61 | myPlacer.setUnitSize(200); 62 | }, 5000); 63 | 64 | // After 10 seconds, change the transition delay when rendering new content and 65 | // then add some new content! (Imagine you queried some API and wanted to render 66 | // new data it had returned...). 67 | setTimeout(function() { 68 | document.getElementById('intro2').className = 'hide'; 69 | document.getElementById('intro3').className = ''; 70 | myPlacer.setDelay(300); 71 | myPlacer.setData(dataArrayExample); 72 | }, 10000); 73 | -------------------------------------------------------------------------------- /js/smartContentPlacer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ContentPlacer v10.0 - A small class which allows you to arrange data of 3 | * different widths / heights such that white space is minimized. 4 | * Coded by Jason Mayes 2014. A present to all the developers out there. 5 | * www.jasonmayes.com 6 | * Please keep this disclaimer with my code if you use it. Thanks. :-) 7 | * Got feedback or questions, ask here: 8 | * https://plus.google.com/u/0/+JasonMayes/posts 9 | * Updates will be posted to this site: 10 | * http://www.jasonmayes.com/projects/contentPlacer/ 11 | * Or see Github: 12 | * https://github.com/jasonmayes/Smart-Content-Placer 13 | * @constructor 14 | * @param {String|HTMLElement} target The DOM element ID/HTMLElement we wish to 15 | * render content in to. 16 | * @param {Number} unitWidthHeight The width and height of the smallest element 17 | * (a square). All 18 | * other elements are whole number multiple of this number. For example if 19 | * your smallest element was 100px by 100px, your other elements should be 20 | * multiples of that eg 200px x 300px (2x3 units). 21 | * @param {Number} margin The margin each element will have. 22 | * @param {Array} dataArray An array of type 23 | * containing content we wish to render. 24 | * @param {Number} renderDelay Optional fade in delay for each item in ms. 25 | */ 26 | var ContentPlacer = function(target, unitSize, margin, dataArray, renderDelay) { 27 | typeof target === 'string' ? 28 | this.target = document.getElementById(target) : this.target = target; 29 | this.unitSize = unitSize; 30 | this.margin = margin; 31 | this.data = dataArray; 32 | this.rowsTot = 1; 33 | this.initiated = false; 34 | this.largestElement = 1; 35 | 36 | // Variables to do with animation. 37 | this.renderDelay = renderDelay; 38 | this.itteration = 0; 39 | this.elemCache = []; 40 | 41 | // Figure out the minimum number of cols by respecting the width of 42 | // largest element. 43 | this.findLargestNode_(); 44 | this.calculateColumns_(); 45 | 46 | var handler = function() { 47 | if (this.data.length > 0) { 48 | var newCols = Math.max(Math.floor(this.target.offsetWidth / (this.unitSize + 49 | this.margin)), this.largestElement); 50 | if (newCols != this.columns) { 51 | this.rowsTot = 1; 52 | this.columns = newCols; 53 | this.render_(); 54 | } 55 | } 56 | } 57 | var boundHandler = handler.bind(this); 58 | this.addEventHandler_(window, 'resize', boundHandler); 59 | this.render_(); 60 | }; 61 | 62 | 63 | /** 64 | * @private 65 | */ 66 | ContentPlacer.prototype.calculateColumns_ = function() { 67 | this.columns = Math.max(Math.floor(this.target.offsetWidth / (this.unitSize + 68 | this.margin)), this.largestElement); 69 | } 70 | 71 | 72 | /** 73 | * @private 74 | */ 75 | ContentPlacer.prototype.findLargestNode_ = function() { 76 | var i = this.data.length; 77 | while (i--) { 78 | if (this.data[i].width > this.largestElement) { 79 | this.largestElement = this.data[i].width; 80 | } 81 | } 82 | } 83 | 84 | 85 | /** 86 | * @private 87 | */ 88 | ContentPlacer.prototype.matrix_ = function(numrows, numcols, initial) { 89 | var arr = []; 90 | for (var y = 0; y < numrows; y++) { 91 | var columns = []; 92 | for (var x = 0; x < numcols; x++) { 93 | columns.push(initial); 94 | } 95 | arr.push(columns); 96 | } 97 | return arr; 98 | }; 99 | 100 | 101 | /** 102 | * @private 103 | */ 104 | ContentPlacer.prototype.growMatrix_ = function(arr, numrows, initial) { 105 | for (var y = 0; y < numrows; y++) { 106 | var columns = []; 107 | for (var x = 0; x < this.columns; x++) { 108 | columns.push(initial); 109 | } 110 | arr.push(columns); 111 | } 112 | return arr; 113 | }; 114 | 115 | 116 | /** 117 | * Attach desired event handler. Cross browser. 118 | */ 119 | ContentPlacer.prototype.addEventHandler_ = function(elem, eventType, handler) { 120 | if (elem.addEventListener) { 121 | elem.addEventListener (eventType, handler, false); 122 | } 123 | else if (elem.attachEvent) { 124 | elem.attachEvent ('on' + eventType, handler); 125 | } 126 | }; 127 | 128 | 129 | /** 130 | * @private 131 | */ 132 | ContentPlacer.prototype.generatePosition_ = function(dataMatrix, unitWidth, 133 | unitHeight) { 134 | var top = 0; 135 | var left = 0; 136 | var x = 0; 137 | var y = 0; 138 | var cols = dataMatrix[x].length; 139 | var rows = dataMatrix.length; 140 | var foundSpot = false; 141 | 142 | function printArray(arr) { 143 | var str = ''; 144 | var cols = arr[0].length; 145 | var rows = arr.length; 146 | var k = 0; 147 | while (k < rows) { 148 | var j = 0; 149 | while (j < cols) { 150 | str += arr[k][j]; 151 | j++; 152 | } 153 | str += '\n'; 154 | k++; 155 | } 156 | console.log(str); 157 | } 158 | 159 | if (unitWidth > this.largestElement) { 160 | this.largestElement = unitWidth; 161 | } 162 | 163 | while (y < rows) { 164 | x = 0; 165 | while (x < cols) { 166 | // Find an empty space. 167 | if (dataMatrix[y][x] === 0) { 168 | // Check that surrounding elements equal to size are also free. 169 | var allGood = true; 170 | // Lets check bounds first. 171 | if ((x + unitWidth - 1) >= cols) { 172 | allGood = false; 173 | } 174 | if ((y + unitHeight - 1) >= rows) { 175 | allGood = false; 176 | } 177 | // If all good so far, then check each space. 178 | if (allGood){ 179 | var j = 0; 180 | while (j < unitWidth) { 181 | var k = 0; 182 | while (k < unitHeight) { 183 | if (dataMatrix[y + k][x + j] !== 0) { 184 | allGood = false; 185 | break; 186 | } 187 | k++; 188 | } 189 | if (!allGood){ 190 | break; 191 | } 192 | j++; 193 | } 194 | } 195 | if (allGood) { 196 | foundSpot = true; 197 | left = (x * (this.unitSize + this.margin)); 198 | top = (y * (this.unitSize + this.margin)); 199 | if ((y + unitHeight) > this.rowsTot) { 200 | this.rowsTot = y + unitHeight; 201 | } 202 | // Now go and claim those spaces as taken. 203 | var j = 0; 204 | while (j < unitWidth) { 205 | var k = 0; 206 | while (k < unitHeight) { 207 | dataMatrix[y + k][x + j] = 1; 208 | k++; 209 | } 210 | j++; 211 | } 212 | // Debug: Show dataMatrix steps. 213 | // printArray(dataMatrix); 214 | break; 215 | } 216 | } 217 | x++; 218 | } 219 | if (foundSpot) { 220 | break; 221 | } 222 | y++; 223 | } 224 | if (foundSpot) { 225 | return {"top": top, "left": left}; 226 | } else { 227 | // If we could not fit in to the current row count, then lets expand our 228 | // rows and try again. 229 | this.growMatrix_(dataMatrix, Math.ceil(dataMatrix.length / 2), 0); 230 | return this.generatePosition_(dataMatrix, unitWidth, unitHeight); 231 | } 232 | }; 233 | 234 | 235 | /** 236 | * @private 237 | */ 238 | ContentPlacer.prototype.render_ = function() { 239 | var data = this.data; 240 | var dataMatrix = this.matrix_(this.rowsTot, this.columns, 0); 241 | var unitSize = this.unitSize; 242 | 243 | if (!this.initiated) { 244 | var frag = document.createDocumentFragment(); 245 | 246 | function itterativeRender() { 247 | if (this.renderDelay !== undefined) { 248 | this.elemCache[this.itteration].setAttribute('class', 249 | 'contentPlacerElement transition'); 250 | } else { 251 | this.elemCache[this.itteration].setAttribute('class', 252 | 'contentPlacerElement'); 253 | } 254 | this.itteration++; 255 | if (this.itteration < this.elemCache.length) { 256 | setTimeout(itterativeRender.bind(this), this.renderDelay); 257 | } 258 | } 259 | 260 | var n = 0; 261 | while (n < data.length) { 262 | var pos = this.generatePosition_(dataMatrix, data[n].width, 263 | data[n].height); 264 | 265 | var div = document.createElement('div'); 266 | div.className = 'contentPlacerElement'; 267 | if (this.renderDelay !== undefined) { 268 | div.className += ' hidden transition'; 269 | } 270 | div.style.width = ((data[n].width * unitSize) + ((data[n].width - 1) * 271 | this.margin)) + 'px'; 272 | div.style.height = ((data[n].height * unitSize) + ((data[n].height - 1) * 273 | this.margin)) + 'px'; 274 | div.style.top = pos.top + 'px'; 275 | div.style.left = pos.left + 'px'; 276 | div.innerHTML = data[n].content; 277 | frag.appendChild(div); 278 | n++; 279 | } 280 | 281 | var rHeight = ((this.rowsTot * unitSize) + ((this.rowsTot - 1) * 282 | this.margin)); 283 | 284 | var container = document.createElement('div'); 285 | container.className = 'contentPlacerContainer'; 286 | container.style.height = rHeight + 'px'; 287 | container.appendChild(frag); 288 | 289 | this.target.appendChild(container); 290 | 291 | this.target.style.height = rHeight + 'px'; 292 | this.target.style.minWidth = ((unitSize + this.margin) * 293 | this.largestElement) + 'px'; 294 | 295 | this.elemCache = document.getElementsByClassName('contentPlacerElement'); 296 | 297 | // If render delay specified, fade in images each after that delay. 298 | if (this.renderDelay !== undefined) { 299 | this.itteration = 0; 300 | setTimeout(itterativeRender.bind(this), 5); 301 | } 302 | this.initiated = true; 303 | } else { 304 | var n = 0; 305 | while(n < data.length) { 306 | var pos = this.generatePosition_(dataMatrix, data[n].width, 307 | data[n].height); 308 | this.elemCache[n].style.top = pos.top + 'px'; 309 | this.elemCache[n].style.left = pos.left + 'px'; 310 | this.elemCache[n].style.width = ((data[n].width * unitSize) + 311 | ((data[n].width - 1) * this.margin)) + 'px'; 312 | this.elemCache[n].style.height = ((data[n].height * unitSize) + 313 | ((data[n].height - 1) * this.margin)) + 'px'; 314 | n++; 315 | } 316 | 317 | // Update height of containers. 318 | var rHeight = ((this.rowsTot * unitSize) + ((this.rowsTot - 1) * 319 | this.margin)); 320 | this.target.style.height = rHeight + 'px'; 321 | this.target.children.item(0).style.height = rHeight + 'px'; 322 | } 323 | }; 324 | 325 | // Public functions to programatically change things after initial instance has 326 | // been created. 327 | 328 | /** 329 | * Set a new margin size. 330 | */ 331 | ContentPlacer.prototype.setMargin = function(marginSizePx) { 332 | this.margin = marginSizePx; 333 | this.columns = Math.max(Math.floor(this.target.offsetWidth / (this.unitSize + 334 | this.margin)), this.largestElement); 335 | this.render_(); 336 | }; 337 | 338 | 339 | /** 340 | * Set a new default unit size. 341 | */ 342 | ContentPlacer.prototype.setUnitSize = function(size) { 343 | this.unitSize = size; 344 | this.columns = Math.max(Math.floor(this.target.offsetWidth / (this.unitSize + 345 | this.margin)), this.largestElement); 346 | this.render_(); 347 | }; 348 | 349 | 350 | /** 351 | * Set new data to use, overwrites existing. 352 | * @param {Array.} dataArray An array containing data we wish to use. 353 | */ 354 | ContentPlacer.prototype.setData = function(dataArr) { 355 | this.data = dataArr; 356 | this.findLargestNode_(); 357 | this.calculateColumns_(); 358 | this.target.innerHTML = ''; 359 | this.initiated = false; 360 | this.render_(); 361 | }; 362 | 363 | 364 | /** 365 | * Add new data to use, appends to existing. 366 | * @param {Array.} dataArray An array containing data we wish to add. 367 | */ 368 | ContentPlacer.prototype.addData = function(dataArr) { 369 | this.data = this.data.concat(dataArr); 370 | this.findLargestNode_(); 371 | this.calculateColumns_(); 372 | this.target.innerHTML = ''; 373 | this.initiated = false; 374 | this.render_(); 375 | }; 376 | 377 | 378 | /** 379 | * Set a new transition delay. 380 | */ 381 | ContentPlacer.prototype.setDelay = function(delayMs) { 382 | this.renderDelay = delayMs; 383 | }; 384 | -------------------------------------------------------------------------------- /js/smartContentPlacer_min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ContentPlacer v10.0 - A small class which allows you to arrange data of 3 | * different widths / heights such that white space is minimized. 4 | * Coded by Jason Mayes 2014. A present to all the developers out there. 5 | * www.jasonmayes.com 6 | * Please keep this disclaimer with my code if you use it. Thanks. :-) 7 | * Got feedback or questions, ask here: 8 | * https://plus.google.com/u/0/+JasonMayes/posts 9 | * Updates will be posted to this site: 10 | * http://www.jasonmayes.com/projects/contentPlacer/ 11 | * Or see Github: 12 | * https://github.com/jasonmayes/Smart-Content-Placer 13 | * @constructor 14 | * @param {String|HTMLElement} target The DOM element ID/HTMLElement we wish to 15 | * render content in to. 16 | * @param {Number} unitWidthHeight The width and height of the smallest element 17 | * (a square). All 18 | * other elements are whole number multiple of this number. For example if 19 | * your smallest element was 100px by 100px, your other elements should be 20 | * multiples of that eg 200px x 300px (2x3 units). 21 | * @param {Number} margin The margin each element will have. 22 | * @param {Array} dataArray An array of type 23 | * containing content we wish to render. 24 | * @param {Number} renderDelay Optional fade in delay for each item in ms. 25 | */ 26 | var ContentPlacer=function(a,c,d,f,g){"string"===typeof a?this.target=document.getElementById(a):this.target=a;this.unitSize=c;this.margin=d;this.data=f;this.rowsTot=1;this.initiated=!1;this.largestElement=1;this.renderDelay=g;this.itteration=0;this.elemCache=[];this.findLargestNode_();this.calculateColumns_();a=function(){if(0this.largestElement&&(this.largestElement=this.data[a].width)};ContentPlacer.prototype.matrix_=function(a,c,d){for(var f=[],g=0;gthis.largestElement&&(this.largestElement=c);for(;e=h&&(m=!1);e+d-1>=p&&(m=!1);if(m)for(var k=0;kthis.rowsTot&&(this.rowsTot=e+d);for(k=0;k