dynamically resize div element with "position: absolute" children - javascript

i'm having the following piece of code:
<head>
<style>
#mainDiv {
background-color: grey;
position: absolute;
}
#one {
height: 150px;
width: 70px;
bottom: 300px;
right: 500px;
background-color: green;
position: absolute;
}
#two {
height: 200px;
width: 200px;
margin-top: 50px;
margin-bottom: 20px;
margin-left: 90px;
margin-right: 5px;
background-color: blue;
position: absolute;
}
</style>
</head>
<body>
<div id="mainDiv">
<div id="one"></div>
<div id="two"></div>
</div>
</body>
i want to resize #mainDiv so it will include its children and will consider all positioning and margin attributes (basically #mainDiv's grey area will surround children and visually show the positioning and margins spaces).
i know it can't be done dynamically using CSS. how can i implement such using pure JavaScript without the use of JQuery?
note: there's no restriction on children's position attribute it can be any of them but "fixed".
code need to support all major browsers + IE8 + mobile (android 2.3 + 4, iphone).
thanks!

Use position relative for second div so the mainDiv greay area will surround your children element
#mainDiv {
background-color: grey;
position: absolute;
}
#one {
height: 150px;
width: 100px;
bottom: 300px;
right: 500px;
background-color: yellow;
}
#two {
height: 200px;
width: 200px;
margin-top: 50px;
margin-bottom: 20px;
margin-left: 90px;
margin-right: 5px;
background-color: blue;
position: relative;
}

I did something maybe complicated that you can find here: http://jsfiddle.net/YMmHz/1/
Basically I get all possible values:
var widthOne, widthTwo, heightOne, heightTwo;
var leftOne, leftTwo, rightOne, rightTwo, topOne, topTwo, botOne, botTwo;
var marginLeftOne, marginLeftTwo, marginRightOne, marginRightTwo, marginTopOne, marginTopTwo, marginBotOne, marginBotTwo;
var paddingLeftOne, paddingLeftTwo, paddingRightOne, paddingRightTwo, paddingTopOne, paddingTopTwo, paddingBotOne, paddingBotTwo;
var maxWidthOne, maxWidthTwo, maxHeightOne, maxHeightTwo;
With different tests:
widthOne = $('#one').width();
widthTwo = $('#two').width();
(parseInt($('#one').css('left')))? leftOne = parseInt($('#one').css('left')):leftOne = 0;
(parseInt($('#two').css('left')))? leftTwo = parseInt($('#two').css('left')):leftTwo = 0;
And then define the size of the #mainDiv like this:
(maxWidthOne>=maxWidthTwo)? $('#main_div').width(maxWidthOne):$('#main_div').width(maxWidthTwo);
(maxHeightOne>=maxHeightTwo)? $('#main_div').height(maxHeightOne):$('#main_div').height(maxHeightTwo);

In your case it's not possible because of some logical reasons.
How is it possible to find a right position for id one when the
parent has no size and therefor no usable right position.
If you are using left instead of right for id one the situation
becomes better.
all the best
try this one
<script>
window.onload = function() {
var elems, max_top, max_right;
elems = mainDiv.getElementsByTagName( 'div' );
for( i = 0; i < elems.length; i++ ) {
elem = elems[ i ].offsetLeft + elems[ i ].offsetWidth + elems[ i ].style.marginLeft;
max_right = ( max_right > elem ) ? max_right : elem;
elem = elems[ i ].offsetTop + elems[ i ].offsetHeight + elems[ i ].style.marginBottom;
max_top = ( max_top > elem ) ? max_top : elem;
}
console.log( 't: ' + max_top + ', r: ' + max_right );
mainDiv.style.height = max_top;
mainDiv.style.width = max_right;
}
</script>
The code is having some problem with getting the margins.
I found a good page which solves the problem.
http://www.quirksmode.org/dom/getstyles.html

Related

How to check if there is any part of element on top using js?

I need to check for given element if there exists any point that elementFromPoint with this point given as argument will return this element. I do not need to find that point - just information if there is at least one. It is equivalent to "if there exists any part of the element which is not covered by another element".
Example: JSFiddle - since there is a part of num2 and num3 which is "on top" desired function should return true for those two. However for num1 result should be false.
I'm not sure if there's a better way than this brute force option of getting the element's boundaries using element.getClientRects(), and then iterating over that area with elementFromPoint to see if it ever returns that element:
var checkIfOnTop = function(el) {
console.log("Checking",el);
var rect = el.getClientRects()[0];
for (var x = rect.left; x <= rect.right; x++) {
for (var y = rect.top; y <= rect.bottom; y++) {
if (document.elementFromPoint(x, y) === el) {
console.log("This element is reachable by click at ",x,y);
return true;
}
}
}
console.log("This element is not reachable by click");
return false;
}
checkIfOnTop(document.getElementById('num1'));
checkIfOnTop(document.getElementById('num2'));
checkIfOnTop(document.getElementById('num3'));
#container { position: relative }
#num1 { position: absolute; left: 50px; height: 200px; width: 200px; background-color: blue}
#num2 { position: absolute; left: 50px; height: 200px; width: 200px; background-color: green}
#num3 { position: absolute; left: 100px; height: 200px; width: 200px; background-color: red}
<div id='container'>
<div id='num1'></div>
<div id='num2'></div>
<div id='num3'></div>
</div>
Not recommended for very large elements, of course.

How do you create 3 adjustable divs?

What I want:
| A | | B | | C |
^ ^
When you move the handles left and right A, B, and C resize accordingly
| A | | B | | C |
What I have is the || between B and C sliding, but not resizing B and all I get on the other one is the resize cursor. Basically C is a curtain and covers A and B. I did get min size working for C.
| A | C |
I broke somebody else's perfectly good code to get this far:
var isResizing = false,
who='',
lastDownX = 0;
$(function () {
var container = $('#container'),
left = $('#left'),
right = $('#right'),
middle = $('#middle'),
hand2 = $('#hand2'),
handle = $('#handle');
handle.on('mousedown', function (e) {
isResizing = true;
who=e.target.id;
lastDownX = e.clientX;
});
$(document).on('mousemove', function (e) {
var temp, min;
// we don't want to do anything if we aren't resizing.
if (!isResizing)
return;
min=container.width() * 0.1;
temp = container.width() - (e.clientX - container.offset().left);
if (temp < min)
temp = min;
if (who == 'handle')
right.css('width', temp);
if (who == 'hand2')
left.css('width', temp);
}).on('mouseup', function (e) {
// stop resizing
isResizing = false;
});
});
body, html {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
#container {
width: 100%;
height: 100%;
/* Disable selection so it doesn't get annoying when dragging. */
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: moz-none;
-ms-user-select: none;
user-select: none;
}
#container #left {
width: 40%;
height: 100%;
float: left;
background: red;
}
#container #middle {
margin-left: 40%;
height: 100%;
background: green;
}
#container #right {
position: absolute;
right: 0;
top: 0;
bottom: 0;
width: 200px;
background: rgba(0, 0, 255, 0.90);
}
#container #handle {
position: absolute;
left: -4px;
top: 0;
bottom: 0;
width: 80px;
cursor: w-resize;
}
#container #hand2 {
position: absolute;
left: 39%;
top: 0;
bottom: 0;
width: 80px;
cursor: w-resize;
}
<div id="container">
<!-- Left side -->
<div id="left"> This is the left side's content!</div>
<!-- middle -->
<div id="middle">
<div id="hand2"></div> This is the middle content!
</div>
<!-- Right side -->
<div id="right">
<!-- Actual resize handle -->
<div id="handle"></div> This is the right side's content!
</div>
</div>
Been playing with it here: https://jsfiddle.net/ju9zb1he/5/
I was looking for a solution that required less extensive CSS. It does have one minor bug(FIXED), but hopefully this should get you started. Here is a DEMO.
Also I aimed to use DOM Traversal methods like .next() and .prev() that way it wouldn't be so attribute dependent, and would be easily reusable if you needed a feature like this multiple times on a page.
Edit - Further Explanation
The idea here is onClick of a .handle we want to gather the total width (var tWidth) of the .prev() and .next() divs relative to the .handle in the DOM. We can then use the start mouse position (var sPos) to substract the amount of pixels we've moved our mouse (e.pageX). Doing so gives us the correct width that the .prev() div should have on mousemove. To get the width of the .next() div we need only to subtract the width of the .prev() div from the total width (var tWidth) that we stored onClick of the .handle. Hope this helps! Let me know if you have any further questions, however I will likely be unavailable till tomorrow.
HTML
<div class="container">
<div id="left"></div>
<div id="l-handle" class="handle"></div>
<div id="middle"></div>
<div id="r-handle" class="handle"></div>
<div id="right"></div>
</div>
CSS
#left, #middle, #right {
display: inline-block;
background: #e5e5e5;
min-height: 200px;
margin: 0px;
}
#l-handle, #r-handle {
display: inline-block;
background: #000;
width: 2px;
min-height: 200px;
cursor: col-resize;
margin: 0px;
}
jQuery
var isDragging = false,
cWidth = $('.container').width(),
sPos,
handle,
tWidth;
$('#left, #middle, #right').width((cWidth / 3) - 7); // Set the initial width of content sections
$('.handle').on('mousedown', function(e){
isDragging = true;
sPos = e.pageX;
handle = $(this);
tWidth = handle.prev().width() + handle.next().width();
});
$(window).on('mouseup', function(e){
isDragging = false;
});
$('.container').on('mousemove', function(e){
if(isDragging){ // Added an additional condition here below
var cPos = sPos - e.pageX;
handle.prev().width((tWidth / 2) - cPos); // This was part of the bug...
handle.next().width(tWidth - handle.prev().width());
// Added an update to sPos here below
}
});
Edit
The bug was caused by 2 things.
1) On mousemove we were dividing the total width by two, instead of an updated mouse offset.
2) The sPos was not updating on mousemove, and stayed a static number based off of the click location.
Resolution
Update the sPos on mousemove that way the mouse offset is accurately based off of the previous mousemove position, rather than the click position. When this is done we can then subtract the .next() div's width from the total width. Then we subtract our current mouse position from the remaining width. The fiddle has been updated as well.
$('.container').on('mousemove', function(e){
var cPos = sPos - e.pageX;
if(isDragging && ((tWidth - handle.next().width()) - cPos) <= tWidth){
handle.prev().width((tWidth - handle.next().width()) - cPos);
handle.next().width(tWidth - handle.prev().width());
sPos = e.pageX;
}
});
Edit
Added an additional condition on mousemove to prevent the drag from exceeding the total width (var tWidth).
Can you please explain what you're trying to accomplish?
I don't believe you need to use position: absolute. The premise of absolute positioning is to override the margin and padding imposed on an element by its parent.
You don't need to do this, all elements have relative positioning by default which makes them push eachother around and don't allow overlapping.
I'm probably missing something, but I think this is what you want with nothing but some very basic CSS: http://jsfiddle.net/3bdoazpk/
<div class='first'>
asdf
</div><div class='second'>
dasdf
</div><div class='third'>
sadf
</div>
body {
margin: 0;
}
div {
display: inline-block;
height: 100%;
}
.first, .third {
width: 40%;
}
.first {
background-color: red;
}
.second {
background-color: blue;
width: 20%;
}
.third {
background-color: green;
}

jitter when using jquery to alter background-position

Here's the jsfiddle.
It's the interface to cropping an image. As you can see the selection div takes the same background image and positions it to the negative of the top and left attributes of the selection div. In theory this should give a perfect overlap, but there's a jitter as you move the selection div around, and I can't seem to figure out what is causing it.
html
<div id="main">
<div id="selection"></div>
</div>
css
#main {
width: 600px;
height: 450px;
position: relative;
background: url("http://cdn-2.historyguy.com/celebrity_history/Scarlett_Johansson.jpg");
background-size: contain;
}
#selection {
width: 100px;
height: 100px;
position: absolute;
background: url("http://cdn-2.historyguy.com/celebrity_history/Scarlett_Johansson.jpg");
border: 1px dotted white;
background-size: 600px 450px;
}
jquery
$(document).ready(function () {
var move = false;
var offset = [];
var selection = null;
$("#selection").mousedown(function (e) {
move = true;
selection = $(this);
offset = [e.pageX - selection.offset().left, e.pageY - selection.offset().top];
});
$("#selection").mousemove(function (e) {
if (move == true) {
selection.css("left", e.pageX - offset[0]);
selection.css("top", e.pageY - offset[1]);
selection.css("background-position", (((-selection.position().left) - 1) + "px " + ((-selection.position().top ) - 1) + "px"));
}
});
$("#selection").mouseup(function (e) {
move = false;
});
})
It would appear that there is a value of 5 offset that needs to be added to ensure seamlessness
DEMO http://jsfiddle.net/nzx0fcp5/2/
offset = [e.pageX - selection.offset().left + 5, e.pageY - selection.offset().top + 5];
So, while experimenting I discovered that this was only a problem at certain sizes of the image. At the original size it is no problem, neither at half nor a quarter of this size. It wasn't simply a matter of keeping the image in proportion not having the image square or using even pixel sizes. I'm assuming this had something to do with partial pixel sizes, but I'm not sure, and I couldn't see any way to work around this, at least none that seemed worth the effort.
So while checking out the code of other croppers I took a look at POF's image cropper, they seem to have got round the problem by not using the background-position property at all (I'm not sure if it's plugin or they coded it themselves). They just set the image down and then used a transparent selection div with 4 divs stuck to each edge for the shading. So there's no pixel crunching on the fly at all. I like the simplicity and lightweight nature of this design and knocked up a version myself in jsfiddle to see if I could get it to work well.
new jitter free jsfiddle with no pixel crunching
I liked the solution for the preview box as well.
html
<body>
<div id="main">
<img src="http://flavorwire.files.wordpress.com/2012/01/scarlett_johansson.jpg" />
<div id="upperShade" class="shade" > </div>
<div id="leftShade" class="shade" > </div>
<div id="selection"></div>
<div id="rightShade" class="shade"></div>
<div id="lowerShade" class="shade" ></div>
</div>
</body>
css
#main {
position:relative;
width: 450px;
height: 600px;
}
#selection {
width: 148px;
height: 148px;
position: absolute;
border: 1px dotted white;
top: 0px;
left: 0px;
z-index: 1;
}
.shade {
background-color: black;
opacity: 0.5;
position: absolute;
}
#upperShade {
top: 0px;
left: 0px;
width: 600px;
}
#leftShade {
left: 0px;
top: 0px;
height: 150px;
width: auto;
}
#rightShade {
left: 150px;
top: 0px;
height: 150px;
width: 450px;
}
#lowerShade {
left:0px;
top: 150px;
width: 600px;
height: 300px;
}
jquery
$(document).ready(function () {
var move = false;
var offset = [];
var selection = null;
$("#selection").mousedown(function (e) {
move = true;
selection = $(this);
offset = [e.pageX - selection.offset().left, e.pageY - selection.offset().top];
});
$("#selection").mousemove(function (e) {
if (move == true) {
selection.css("left", e.pageX - offset[0]);
selection.css("top", e.pageY - offset[1]);
setShade();
}
});
function setShade() {
$("#upperShade").css("height", selection.position().top);
$("#lowerShade").css("height", 600 - (selection.position().top + 150));
$("#lowerShade").css("top", selection.position().top + 150);
$("#leftShade").css("top", selection.position().top);
$("#leftShade").css("width", selection.position().left);
$("#rightShade").css("top", selection.position().top);
$("#rightShade").css("left", selection.position().left + 150);
$("#rightShade").css("width", 450 - selection.position().left);
}
$("#selection").mouseup(function (e) {
move = false;
});
});

Alter .css with JS? Setting dynamic .css properties with variables

I have something like the below:
<div id="left">
left
</div>
<div id="right">
right
</div>
With .css properties:
#left {
width: 60%;
float: left
min-height: ###
max-height: 1000px;
}
#right {
width: 40%;
float: right;
min-height: ###
max-height: 1000px;
}
Notice the ### for both <div> CSS min-height properties. I'd like something like the below (some pseudo JS):
var leftheight = document.getElementById(left);
var rightheight = document.getElementById(right);
if (leftheight.currentHeight > rightheight.currentHeight) {
rightheight.style.min-height = leftheight.currentHeight;
} else if (rightheight.currentHeight > leftheight.currentHeight) {
leftheight.style.min-height = rightheight.currentHeight;
}
Basically I want:
if (current height of left > current height of right) {
min-height of right = current height of left
} else if (current height of right > current height of left) {
min-height of left = current height of right
}
//ie. both left and right have the same min-heights, whichever is larger
My Javascript is wrong, and it's something I'm learning just now. Is there a method I can use to get my desired results?
You can do this:
if (leftheight.currentHeight > rightheight.currentHeight) {
rightheight.style.minHeight = leftheight.currentHeight;
} else if (rightheight.currentHeight > leftheight.currentHeight) {
leftheight.style.minHeight = rightheight.currentHeight;
}
It's actually minHeight not min-height.
There is no need for javascript here, you can achieve this by adding a container with overflow: hidden and adding positive and negative margins to the left and right divs:
<div id="container">
<div id="left">left</div>
<div id="right">right<br /><br /><br /><br />Foobar</div>
</div>
#container {
width: 75%; /* amend this as required */
overflow: hidden;
}
#left {
width: 60%;
float: left;
max-height: 1000px;
background-color: #C00;
padding-bottom: 1000px;
margin-bottom: -1000px;
}
#right {
width: 40%;
float: right;
max-height: 1000px;
background-color: #0C0;
padding-bottom: 1000px;
margin-bottom: -1000px;
}
Example fiddle
As a rule, javascript should never be used solely for layout purposes. What would happen to your page if someone has javascript turned off?
you can use jquery
var leftheight = $('#left').height();
var rightheight =$('#right').height();
if (leftheight > rightheight) {
$('#right').css('min-height',leftheight+"px")
}
else if (rightheight > leftheight) {
$('#left').css('min-height',rightheight + "px")
}
using jquery
$(function(){ //ready function to make sure document is ready
var $leftdiv=$('#left'),
$rightdiv=$('#right'),
$leftHeight=$('#left').height(),
$rightHeight=$('#right').height();
if ( $leftHeight > $rightHeight) {
$rightdiv.css('min-height':$leftHeight + "px");
} else if ( $rightHeight > $leftHeight) {
$leftdiv.css('min-height':$rightHeight + "px");
}
});

Doing a roll-in/roll-out slideshow in jQuery

I am trying to create a roll-in / roll-out slideshow in jQuery/JavaScript.
My problem is, that it needs to be repeated. And right now when it's starting over, the pictures doesnt come from the right side anymore :(
The reason for which I have created the slideLeft function, is that afterwards I need to create 2 functions, where the user can interrupt the slideshow manually pressing a left or right button.
This is what I've got:
<script class="jsbin" src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<div style='background: #c4c4c4; border: 1px solid #7b7b7b; height: 220px; overflow: hidden; padding: 5px; position: absolute; width: 590px;'>
<div id='slider-image-1' style='left: 5px; background: red; height: 216px; padding: 2px; position: absolute; top: 5px; width: 586px;'></div>
<div id='slider-image-2' style='left: 600px; background: yellow; height: 216px; padding: 2px; position: absolute; top: 5px; width: 586px;'></div>
<div id='slider-image-3' style='left: 600px; background: green; height: 216px; padding: 2px; position: absolute; top: 5px; width: 586px;'></div>
<div id='slider-image-4' style='left: 600px; background: blue; height: 216px; padding: 2px; position: absolute; top: 5px; width: 586px;'></div>
</div>
<script type='text/javascript'>
$(document).ready(function() {
var amount = 0;
var nextamount = 1;
setInterval(function() {
amount++;
nextamount++;
if (nextamount === 5) nextamount = 1;
if (amount === 5) amount = 1;
slideLeft(amount, nextamount);
}, 2000);
});
function slideLeft(i, j) {
var $theItem = $('#slider-image-' + i);
$theItem.animate({
left: parseInt($theItem.css('left'), 10) == 5 ? -$theItem.outerWidth() : 5
}, 500);
var $theItem = $('#slider-image-' + j);
$theItem.animate({
left: parseInt($theItem.css('left'), 10) == 5 ? $theItem.outerWidth() + 10 : 5
}, 500);
};
</script>
You need to prepare element, which is going to roll in, to be on the right.
function slideLeft(i, j) {
var $theItem = $('#slider-image-' + i);
$theItem.animate({
left: parseInt($theItem.css('left'), 10) == 5 ? -$theItem.outerWidth() : 5
}, 500);
var $theItem = $('#slider-image-' + j);
$theItem.css('left', '600px'); // moves in item to the right before animation
$theItem.animate({
left: parseInt($theItem.css('left'), 10) == 5 ? $theItem.outerWidth() + 10 : 5
}, 500);
};
I think you've tried it with your parseInt, but it doesn't work, so you can get rid of it.
function slideLeft(i, j) {
var $outItem = $('#slider-image-' + i);
$outItem.animate({ left: -$outItem.outerWidth() }, 500);
var $inItem = $('#slider-image-' + j);
$inItem.css('left', '600px');
$inItem.animate({ left: 5 }, 500);
}
I have made something like this before, i dont know if this will help you, what i did was:
Add a copy of the first slide in the end of the collection of images/slides. Then, when you are showing the last "real" image and it will look like you are scrolling to the first image (but that is just a copy of the first image), and then when the animation is done you can position it with the default "left" css value. If you want it to scroll both ways, you can do the same with a copy of the last image/slide before the first image, but then you'll have to start the slider with a offset.
its a bit hard to explain, do you get the point? :)

Categories

Resources