How to get the hovered div position - css

I want my tooltip to be aligned next to the hovered element. How can I find the position of hovered element such that it works in devices also. I am passing the hovered element event on mouseenter.
I tried setting the ClientX, ClientY or screenX, ScreenY position to top and left but it's not working properly.

Example
As you dont provided any code source I created a sample to show what you can do:
var ul = document.querySelector('ul');
var li = ul.querySelectorAll('li');
var tooltip = document.querySelector('.tooltip');
var removeTooltip;
function onMouseOver(e) {
return function() {
clearTimeout(removeTooltip);
tooltip.innerHTML = e.innerHTML;
var w = window;
var tooltipTopPosition = e.offsetTop + (e.clientHeight / 2) - (tooltip.clientHeight / 2);
var leftPosition = e.offsetLeft + e.offsetWidth + 5;
var toolTipWidth = w.innerWidth - leftPosition - 5;
tooltip.style.top = tooltipTopPosition + 'px';
tooltip.style.left = leftPosition + 'px';
tooltip.style.width = toolTipWidth + 'px';
}
}
function onMouseLeave(e) {
return function() {
clearTimeout(removeTooltip);
removeTooltip = setTimeout(function() {
tooltip.innerHTML = '';
}, 100);
};
}
li.forEach(function(item) {
item.onmouseover = onMouseOver(item);
item.onmouseleave = onMouseLeave(item);
});
.tooltip {
background: rgba(0,0,0,0.9);
color: #ffffff;
position: absolute;
z-index: 1000;
word-break: break-all;
white-space: normal;
}
ul {
width: 200px;
margin: 50px auto 0;
padding: 0;
}
ul li {
list-style-type: none;
background: #ccc;
padding: 5px;
border: 1px dotted;
}
<ul>
<li>Lorem.</li>
<li>Necessitatibus.</li>
<li>Dolorum.</li>
<li>Est.</li>
</ul>
<div class="tooltip"></div>

Related

section content scaling with background

I am trying to stop my section content from scaling with my section background. the scale of the background is perfect but it seems to make the content scale also, I am using gsap library I have tried creating a container inside the section and give it absolute but nothing I do stops the content inside from scaling
//First the variables our app is going to use need to be declared
//References to DOM elements
var $window = $(window);
var $document = $(document);
//Only links that starts with #
var $navButtons = $("nav a").filter("[href^=#]");
var $navGoPrev = $(".go-prev");
var $navGoNext = $(".go-next");
var $sectionsContainer = $(".sections-container");
var $sections = $(".section");
var $currentSection = $sections.first();
//Animating flag - is our app animating
var isAnimating = false;
//The height of the window
var pageHeight = $window.innerHeight();
//Key codes for up and down arrows on keyboard. We'll be using this to navigate change sections using the keyboard
var keyCodes = {
UP : 38,
DOWN: 40
}
//Going to the first section
goToSection($currentSection);
/*
* Adding event listeners
* */
$window.on("resize", onResize).resize();
$window.on("mousewheel DOMMouseScroll", onMouseWheel);
$document.on("keydown", onKeyDown);
$navButtons.on("click", onNavButtonClick);
$navGoPrev.on("click", goToPrevSection);
$navGoNext.on("click", goToNextSection);
/*
* Internal functions
* */
/*
* When a button is clicked - first get the button href, and then section to the container, if there's such a container
* */
function onNavButtonClick(event)
{
//The clicked button
var $button = $(this);
//The section the button points to
var $section = $($button.attr("href"));
//If the section exists, we go to it
if($section.length)
{
goToSection($section);
event.preventDefault();
}
}
/*
* Getting the pressed key. Only if it's up or down arrow, we go to prev or next section and prevent default behaviour
* This way, if there's text input, the user is still able to fill it
* */
function onKeyDown(event)
{
var PRESSED_KEY = event.keyCode;
if(PRESSED_KEY == keyCodes.UP)
{
goToPrevSection();
event.preventDefault();
}
else if(PRESSED_KEY == keyCodes.DOWN)
{
goToNextSection();
event.preventDefault();
}
}
/*
* When user scrolls with the mouse, we have to change sections
* */
function onMouseWheel(event)
{
//Normalize event wheel delta
var delta = event.originalEvent.wheelDelta / 30 || -event.originalEvent.detail;
//If the user scrolled up, it goes to previous section, otherwise - to next section
if(delta < -1)
{
goToNextSection();
}
else if(delta > 1)
{
goToPrevSection();
}
event.preventDefault();
}
/*
* If there's a previous section, section to it
* */
function goToPrevSection()
{
if($currentSection.prev().length)
{
goToSection($currentSection.prev());
}
}
/*
* If there's a next section, section to it
* */
function goToNextSection()
{
if($currentSection.next().length)
{
goToSection($currentSection.next());
}
}
/*
* Actual transition between sections
* */
function goToSection($section)
{
//If the sections are not changing and there's such a section
if(!isAnimating && $section.length)
{
//setting animating flag to true
isAnimating = true;
//Sliding to current section
TweenLite.set($currentSection, {autoAlpha: 0, display: 'none'});
$currentSection = $section;
TweenLite.set($currentSection, {display: 'block'});
TweenLite.fromTo($currentSection, 0.6, {scale: 0.9, autoAlpha: 0}, {scale: 1, autoAlpha: 1, ease: Power1.easeOut, onComplete: onSectionChangeEnd, onCompleteScope: this});
//Animating menu items
TweenLite.to($navButtons.filter(".active"), 0.5, {className: "-=active"});
TweenLite.to($navButtons.filter("[href=#" + $currentSection.attr("id") + "]"), 0.5, {className: "+=active"});
}
}
/*
* Once the sliding is finished, we need to restore "isAnimating" flag.
* You can also do other things in this function, such as changing page title
* */
function onSectionChangeEnd()
{
isAnimating = false;
}
/*
* When user resize it's browser we need to know the new height, so we can properly align the current section
* */
function onResize(event)
{
//This will give us the new height of the window
var newPageHeight = $window.innerHeight();
/*
* If the new height is different from the old height ( the browser is resized vertically ), the sections are resized
* */
if(pageHeight !== newPageHeight)
{
pageHeight = newPageHeight;
//This can be done via CSS only, but fails into some old browsers, so I prefer to set height via JS
TweenLite.set([$sectionsContainer, $sections], {height: pageHeight + "px"});
//The current section should be always on the top
TweenLite.set($sectionsContainer, {scrollTo: {y: pageHeight * $currentSection.index() }});
}
}
body, div, p {
margin: 0;
padding: 0;
}
body {
font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
font-weight: 300;
letter-spacing: 0.0625em;
background-color: #000;
}
h1{
color: #fff;
}
.sections-container {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: hidden;
z-index: 10;
}
.section {
position: absolute;
width: 100%;
height: 100%;
overflow: hidden;
display: none;
visibility: hidden;
opacity: 0;
}
#section-1 {
display: block;
visibility: visible;
opacity: 1;
}
.section .centered h1 {
text-align: center;
}
.section .centered p {
text-align: center;
}
#section-1 {
background-color: #5A4748;
}
#section-2 {
background-color: #45959b;
}
#section-3 {
background-color: #778899;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenLite.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/plugins/CSSPlugin.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/plugins/ScrollToPlugin.min.js"></script>
<div class="sections-container">
<div class="section" id="section-1">
<div class="centered">
<h1>1</h1>
</div>
</div>
<div class="section" id="section-2">
<div class="centered">
<h1>2</h1>
</div>
</div>
<div class="section" id="section-3">
<div class="centered">
<h1>3</h1>
</div>
</div>
</div>
Would this be what you're looking for? I basically added a background div
<div id="background"></div>
#background {
position: absolute;
width: 100%;
height: 100%;
overflow: hidden;
display: block;
visibility: visible;
opacity: 1;
}
which is assigned a background class based on the section which is currently visible.
var $background = $("#background");
...
$background.classList = "";
TweenLite.set($background, {
className: '+=bg-' + ($sections.index($currentSection) + 1)
});
TweenLite.fromTo($background, 0.6, {
scale: 0.9,
autoAlpha: 0
}, {
scale: 1,
autoAlpha: 1,
ease: Power1.easeOut,
onComplete: onSectionChangeEnd,
onCompleteScope: this
});
You can choose to remove the autoAlpha tween on the section numbers if you so prefer.
//First the variables our app is going to use need to be declared
//References to DOM elements
var $window = $(window);
var $document = $(document);
//Only links that starts with #
var $navButtons = $("nav a").filter("[href^=#]");
var $navGoPrev = $(".go-prev");
var $navGoNext = $(".go-next");
var $sectionsContainer = $(".sections-container");
var $sections = $(".section");
var $background = $("#background");
var $currentSection = $sections.first();
//Animating flag - is our app animating
var isAnimating = false;
//The height of the window
var pageHeight = $window.innerHeight();
//Key codes for up and down arrows on keyboard. We'll be using this to navigate change sections using the keyboard
var keyCodes = {
UP: 38,
DOWN: 40
}
//Going to the first section
goToSection($currentSection);
/*
* Adding event listeners
* */
$window.on("resize", onResize).resize();
$window.on("mousewheel DOMMouseScroll", onMouseWheel);
$document.on("keydown", onKeyDown);
$navButtons.on("click", onNavButtonClick);
$navGoPrev.on("click", goToPrevSection);
$navGoNext.on("click", goToNextSection);
/*
* Internal functions
* */
/*
* When a button is clicked - first get the button href, and then section to the container, if there's such a container
* */
function onNavButtonClick(event) {
//The clicked button
var $button = $(this);
//The section the button points to
var $section = $($button.attr("href"));
//If the section exists, we go to it
if ($section.length) {
goToSection($section);
event.preventDefault();
}
}
/*
* Getting the pressed key. Only if it's up or down arrow, we go to prev or next section and prevent default behaviour
* This way, if there's text input, the user is still able to fill it
* */
function onKeyDown(event) {
var PRESSED_KEY = event.keyCode;
if (PRESSED_KEY == keyCodes.UP) {
goToPrevSection();
event.preventDefault();
} else if (PRESSED_KEY == keyCodes.DOWN) {
goToNextSection();
event.preventDefault();
}
}
/*
* When user scrolls with the mouse, we have to change sections
* */
function onMouseWheel(event) {
//Normalize event wheel delta
var delta = event.originalEvent.wheelDelta / 30 || -event.originalEvent.detail;
//If the user scrolled up, it goes to previous section, otherwise - to next section
if (delta < -1) {
goToNextSection();
} else if (delta > 1) {
goToPrevSection();
}
event.preventDefault();
}
/*
* If there's a previous section, section to it
* */
function goToPrevSection() {
console.log($currentSection.prev().length > 0);
if ($currentSection.prev().length) {
goToSection($currentSection.prev());
}
}
/*
* If there's a next section, section to it
* */
function goToNextSection() {
if ($currentSection.next().length > 0) {
goToSection($currentSection.next());
}
}
/*
* Actual transition between sections
* */
function goToSection($section) {
//If the sections are not changing and there's such a section
if (!isAnimating && $section.length) {
//setting animating flag to true
isAnimating = true;
//Sliding to current section
TweenLite.set($currentSection, {
autoAlpha: 0,
display: 'none'
});
$currentSection = $section;
$background.classList = "";
TweenLite.set($currentSection, {
display: 'block'
});
TweenLite.set($background, {
className: 'bg-' + ($sections.index($currentSection) + 1)
});
//console.log($sections.index($currentSection) + 1);
TweenLite.fromTo($background, 0.6, {
scale: 0.9,
autoAlpha: 0
}, {
scale: 1,
autoAlpha: 1,
ease: Power1.easeOut,
onComplete: onSectionChangeEnd,
onCompleteScope: this
});
TweenLite.fromTo($currentSection, 0.6, {
autoAlpha: 0
}, {
autoAlpha: 1,
ease: Power1.easeOut,
});
//Animating menu items
TweenLite.to($navButtons.filter(".active"), 0.5, {
className: "-=active"
});
TweenLite.to($navButtons.filter("[href=#" + $currentSection.attr("id") + "]"), 0.5, {
className: "+=active"
});
}
}
/*
* Once the sliding is finished, we need to restore "isAnimating" flag.
* You can also do other things in this function, such as changing page title
* */
function onSectionChangeEnd() {
isAnimating = false;
}
/*
* When user resize it's browser we need to know the new height, so we can properly align the current section
* */
function onResize(event) {
//This will give us the new height of the window
var newPageHeight = $window.innerHeight();
/*
* If the new height is different from the old height ( the browser is resized vertically ), the sections are resized
* */
if (pageHeight !== newPageHeight) {
pageHeight = newPageHeight;
//This can be done via CSS only, but fails into some old browsers, so I prefer to set height via JS
TweenLite.set([$sectionsContainer, $sections], {
height: pageHeight + "px"
});
//The current section should be always on the top
TweenLite.set($sectionsContainer, {
scrollTo: {
y: pageHeight * $currentSection.index()
}
});
}
}
body,
div,
p {
margin: 0;
padding: 0;
}
body {
font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif;
font-weight: 300;
letter-spacing: 0.0625em;
background-color: #000;
}
h1 {
color: #fff;
}
.sections-container {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: hidden;
z-index: 10;
}
.section {
position: absolute;
width: 100%;
height: 100%;
overflow: hidden;
display: none;
visibility: hidden;
opacity: 0;
}
#section-1 {
display: block;
visibility: visible;
opacity: 1;
}
.section .centered h1 {
text-align: center;
}
.section .centered p {
text-align: center;
}
#background {
position: absolute;
width: 100%;
height: 100%;
overflow: hidden;
display: block;
visibility: visible;
opacity: 1;
}
.bg-1 {
background-color: #5A4748;
}
.bg-2 {
background-color: #45959b;
}
.bg-3 {
background-color: #778899;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/TweenLite.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/plugins/CSSPlugin.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/latest/plugins/ScrollToPlugin.min.js"></script>
<div id="background"></div>
<div class="sections-container">
<div class="section" id="section-1">
<div class="centered">
<h1>1</h1>
</div>
</div>
<div class="section" id="section-2">
<div class="centered">
<h1>2</h1>
</div>
</div>
<div class="section" id="section-3">
<div class="centered">
<h1>3</h1>
</div>
</div>
</div>

Text underlined by a single line of two colors

Good morning. Hello,
I'm looking to underline a title with a line of two colors. Half blue, half black, for example.
I imagine it's done by CSS, but I haven't figured out how to do it.
Does anyone have the solution?
Thank you all, happy holidays.
You can use :before and :after pseudo-elements for each half of the line. If you want to increase line height you also need to increase negative margin on :after pseudo-element for the same amount. Demo
h1 {
display: inline-flex;
flex-direction: column;
}
h1:after,
h1:before {
content: '';
border-bottom: 1px solid green;
order: 2;
width: 50%;
}
h1:after {
margin-left: auto;
margin-top: -1px;
border-color: red;
}
<h1>Lorem ipsum dolor sit.</h1>
If you have multi-line title then you can split text into two spans and use text-decoration instead.
h1 {
max-width: 400px;
}
h1 span:first-child {
text-decoration: red underline;
}
h1 span:last-child {
text-decoration: green underline;
}
<h1><span>Lorem ipsum dolor </span><span>sit amet, consectetur.</span></h1>
You could use some js to create more dynamic solution.
class Title {
constructor(text, parts = []) {
this.text = text;
this.parts = parts;
return this.create()
}
checkLength() {
let l = this.parts.reduce((r, e) => r + e.width, 0);
if (l > 100) {
throw new Error('Sum of all parts width must be under 100%')
}
}
create() {
this.checkLength();
let title = this.createTitle();
this.addLines(title);
return title;
}
createTitle() {
let h1 = document.createElement('h1');
h1.textContent = this.text;
h1.style.display = 'inline-block';
h1.style.position = 'relative';
return h1;
}
createLine(input) {
let {color,width} = input;
let line = document.createElement('span');
line.style.position = 'absolute';
line.style.bottom = 0;
line.style.border = '1px solid ' + color;
line.style.width = width + '%';
return line;
}
addLines(title) {
let that = this;
this.parts.forEach(function(part) {
let line = that.createLine(part);
line.style.left = this.prev + '%';
this.prev += part.width;
title.appendChild(line)
}, {prev: 0})
}
}
let title = new Title('Random Title', [
{color: 'red', width: 60},
{color: 'blue', width: 20},
{color: 'green', width: 20}
])
let title2 = new Title('Lorem ipsum dolor.', [
{color: 'black', width: 80},
{color: 'green', width: 20}
])
document.body.appendChild(title)
document.body.innerHTML += '<br>'
document.body.appendChild(title2)

Dynamic Text with surrounding line, whose container has a background image

I need to implement something like this..
-------------------------
| |
| |
|---- dynamic text --- |
| |
-------------------------
I want the line surrounding the "dynamic text" in css.
I tried using &::before and &::after css, but still when the dynamic text changes i need to stretch/decrease that one. Any ideas?
You could use JavaScript to set the width of :before and :after :pseudo-elements dynamically.
function foo() {
var ss = document.styleSheets;
var text = document.getElementById('text');
var box = document.getElementById('box');
var totalWidth = getComputedStyle(box).width.slice(0, -2);
var textWidth = text.offsetWidth;
var lineWidth;
var margin = 4; // Set the margin between text and line.
for (i = 0; i < ss.length; i++) {
var rules = ss[i];
for (j = 0; j < rules.cssRules.length; j++) {
var r = rules.cssRules[j];
if (r.selectorText == "#text:before") {
// If you want the margin to be set on both sides of the line,
// replace 'margin' with '(margin * 2)' in the next line.
lineWidth = ((totalWidth / 2) - (textWidth / 2) - margin);
r.style.width = lineWidth + 'px';
r.style.left = -(lineWidth + margin) + 'px';
} else if (r.selectorText == "#text:after") {
r.style.width = lineWidth + 'px';
r.style.right = -(lineWidth + margin) + 'px';
}
}
}
}
foo();
#box {
width: 300px;
height: 200px;
background-color: #FF0000;
line-height: 200px;
text-align: center;
}
#text {
position: relative;
background-color: rgba(0, 0, 0, 0.5);
border-radius: 10px;
padding: 4px;
color: white;
}
#text:before {
content: "";
position: absolute;
border-bottom: 1px solid black;
height: 100px;
}
#text:after {
content: "";
position: absolute;
border-bottom: 1px solid black;
height: 100px;
}
<div id="box"><span id="text">This is the text which is dynamic</span>
</div>
<div id="divWithBackground">
<div id="divActsAsLine">
<span id="DynamicText">Your text here </span>
</div>
</div>
Now the CSS
#divActsAsLine{
border-botton:1px solid #00;
text-align:center;
}
#DynamicText{
position:relative;
background-color: #fff;
margin-bottom:-20px /*Adjust this based on your requirements*/
z-index:1 /* optional */
}
The logic is to make a div margin as background line and make the span overlap this line, to do this we need to either decrease or increase margin property. you might need to use z-index if necessary

jQuery UI Droppable block by absolute div

How can a jquery ui droppable be blocked by an overlaid div?
See this example: http://jsfiddle.net/JSFU4/3/. A red div is overlaying the droppable area; however, when dragging on top of this area, the droppable is still activated. How can this be avoided?
Html
<div>
<div class="drop">drop here</div>
</div>
<div>
<div class="drag">drag me</div>
</div>
<div class="overlay">i want to block the droppable</div>
CSS
.drag {
display: inline-block;
width: 100px;
height: 100px;
border: 1px solid black;
background-color: lightblue;
z-index: 1;
}
.drop {
display: inline-block;
border: 1px dotted black;
width: 200px;
height: 200px;
}
.drop-hover {
background-color: grey;
}
.overlay {
position: absolute;
width: 300px;
height: 100px;
top: 50px;
background-color: red;
border: 1px solid black;
}
JS
$(function () {
$('.drag').draggable();
$('.drop').droppable({
tolerance: 'pointer',
hoverClass: 'drop-hover'
});
});
I don't think there is anything out of box to achieve this. You need to do some kind of collision detection and then do your logic accordingly. I have done a POC for you.
DEMO
var drag = $('.drag');
var overlay = $('.overlay');
$(function () {
$('.drag').draggable();
$('.drop').droppable({
tolerance: 'pointer',
hoverClass: 'drop-hover'
});
});
var int = self.setInterval(function () {
if (overlaps(drag, overlay)) {
$('.drop').css('visibility', 'hidden');
} else {
$('.drop').css('visibility', 'visible');
}
}, 100);
var overlaps = (function () {
function getPositions(elem) {
var pos, width, height;
pos = $(elem).position();
width = $(elem).width() / 2;
height = $(elem).height();
return [[pos.left, pos.left + width], [pos.top, pos.top + height]];
}
function comparePositions(p1, p2) {
var r1, r2;
r1 = p1[0] < p2[0] ? p1 : p2;
r2 = p1[0] < p2[0] ? p2 : p1;
return r1[1] > r2[0] || r1[0] === r2[0];
}
return function (a, b) {
var pos1 = getPositions(a),
pos2 = getPositions(b);
return comparePositions(pos1[0], pos2[0]) && comparePositions(pos1[1], pos2[1]);
};
})();
The code above detects the collision between two DIVs and returns true or false.

css: float blocks to occupy all free space

I'm trying to make an "image mosaic" that consists mostly of images of the same size, and some of them the double height.
They all should align neatly like this:
To make automatic generation of those mosaic as easy as possible, I thought floating them would be the best option. Unfortunately, the big block causes the following ones to flow behind it, but not before:
What can I do - apart from manually positioning them - to get the images to the place I want, and still have it easy to automatically create likewise layouts?
The code I'm currently using is :
FIDDLE
HTML :
<div class="frame">
<div id="p11" class="img">1.1</div>
<div id="p12" class="img h2">1.2</div>
<div id="p13" class="img">1.3</div>
<div id="p21" class="img">2.1</div>
<div id="p22" class="img">2.2</div>
</div>
CSS :
.frame {
background-color: blue;
border: 5px solid black;
width: 670px;
}
.img {
width: 200px;
height: 125px;
background-color: white;
border: 1px solid black;
float: left;
margin: 10px;
}
.h2 {
height: 272px;
}
You need to use Javascript to achieve this effect, I had to do that once and I used http://masonry.desandro.com/ -- worked well!
Pure CSS Solution
Tested in Firefox, IE8+ (IE7 looks like it would need to be targeted to add a top margin added to 2.1 because it overlaps 1.1). See fiddle. This assumes .h2 is the middle div (as your example). If left most div it should not need any change. If right most, you would need to expand the negative margin to also include the third div following.
.h2 + div {
float: right;
margin: 10px 14px 10px 0; /*14px I believe also has to do with borders */
}
.h2 + div + div {
margin-left: -434px; /*need to account for borders*/
clear: right;
}
You can use a column layout like this:
http://jsfiddle.net/KKUZL/
I don't know if that will conflict with your automation process though....
I realize this is not a CSS-only solution, but for what it's worth (JSFiddle):
HTML:
<div id='container'></div>
CSS:
html, body {
margin:0px;
padding:0px;
height:100%;
}
body {
background-color:#def;
}
#container {
margin:0px auto;
width:635px;
min-height:100%;
background-color:#fff;
box-shadow:0px 0px 5px #888;
box-sizing:border-box;
overflow:auto;
}
.widget {
float:left;
box-sizing:border-box;
padding:10px 10px 0px 0px;
}
.widget > div{
height:100%;
box-sizing:border-box;
color:#fff;
font-size:3em;
text-align:center;
padding:.5em;
overflow:hidden;
}
.widget > div:hover {
background-color:purple !important;
}
JS:
////////////////////////////////////////
// ASSUMPTIONS
//
var TWO_COLUMN_WIDGET_COUNT = 1;
var ONE_COLUMN_WIDGET_COUNT = 15;
var NUMBER_OF_COLUMNS = 2;
////////////////////////////////////////
function rand(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var colorFactory = (function () {
var colors = [
'#CC9A17',
'#9B2C16',
'#1A8B41',
'#D97114',
'#3B9EE6'];
var index = 0;
return function () {
if (index > 4) {
index = 0;
}
return colors[index++];
}
})();
function widgetFactory(columnSpan) {
return {
'height': rand(10, 30) * 10,
'width': 100 * columnSpan / NUMBER_OF_COLUMNS,
'columnSpan': columnSpan,
'color': colorFactory()
}
}
function getWidgets() {
var widgets = [];
for (var i = 0; i < TWO_COLUMN_WIDGET_COUNT; i++) {
widgets.push(widgetFactory(2));
}
for (var i = 0; i < ONE_COLUMN_WIDGET_COUNT; i++) {
widgets.push(widgetFactory(1));
}
return widgets;
}
function getHighestOffset(offsets){
}
function getHighestSlot(offsets, numOfColumns){
}
$(document).ready(function () {
var container = $('#container');
var widgets = getWidgets();
var col1 = Math.floor(container[0].offsetLeft);
var col2 = Math.floor(container[0].clientWidth / 2 + container[0].offsetLeft);
var offsets = {};
offsets[col1] = 0;
offsets[col2] = 0;
var newLine = true;
for (var i = 0; i < widgets.length; i++) {
var w = widgets[i];
var marginTop = 0;
if (offsets[col1] < offsets[col2]) {
marginTop = (offsets[col2] - offsets[col1]) * -1;
}
if(offsets[col1] <= offsets[col2] || w.columnSpan == 2){
newLine = true;
}
var margin = 'margin-top:' + marginTop + 'px;';
var height = 'height:' + w.height + 'px;';
var color = 'background-color:' + colorFactory() + ';';
var width = 'width:' + w.width + '%;';
var padding = newLine ? "padding-left:10px;" : "";
var component = $('<div class="widget" style="' + padding + margin + height + width + '"><div style="' + color + '">' + i + '</div></div>');
component.appendTo(container);
var c = component[0];
var index = 0;
var minOffset = null;
for(var p in offsets){
if(minOffset == null || offsets[p] < minOffset){
minOffset = offsets[p];
}
if(p == Math.floor(c.offsetLeft)){
index = 1;
}
if(index > 0 && index <= w.columnSpan){
offsets[p] = c.offsetTop + c.offsetHeight;
index++;
}
}
newLine = minOffset >= offsets[col1];
}
});

Resources