How to add a div as a background for another? - javascript

My goal is to dynamically generate background images for divs.
I've got a function that:
Draws an image on canvas;
Gets data URL of the image;
Creates a bgDiv with the image as background;
Prepends the bgDiv to a given div element.
Here's the code of the 3rd and 4th points:
var bgDiv = document.createElement('div');
$(bgDiv).css({
position: 'absolute',
left: '0px',
top: '0px',
width: '100%',
height: '100%',
background: 'url(' + url + ')',
});
$(div).prepend(bgDiv);
The problem is: the bgDiv is drawn in front of children of div. I've figured out this is because of the position: absolute property, which is set on bgDiv while regular children in my case have no position set.
How can I get the bgDiv element to be drawn on the bottom of all children no matter what they are?
Disclaimer: I know that I could just set background-image property of div, but it's not sufficient for my purposes.
I'm testing this in recent Firefox, and I need quite universal solution.

Edit: if you're actually using $(div) as your selector, that's one problem. Use the content <div>'s ID or class instead.
Edit 2: If you're doing this multiple times (with different background images) I'd make bgDiv a class instead, then dynamically assign their positions. It will save you some JS.
bgDiv has to be "below" the rest of the div content, so give it a lower z-index than that of the content; this could cause it to fall underneath another element, however. In this case, set the content of the div to a higher z-index (and leave bgDiv's z-index to the default auto).
.bgDiv {
position: 'absolute';
z-index:-1;
/* left: '0px'; Set in JS */
/* top: '0px'; Set in JS */
width: '100%';
height: '100%';
/* background: 'url(' + url + ')'; Set in JS */
}

You defined your problem correctly in your question, you need to have bgDiv draw in a position lower than the children of div. In other words you need to set the z-index of all children to be higher, if you need to do this programatically then do
var bgDiv = $('<div class="bgDiv">').css('background', 'url(' + url + ')');
$(div).children().css({zIndex,2});
$(div).prepend(bgDiv);
With a defined class bgDiv in your CSS as #trojansdestroy suggested
.bgDiv {
position: absolute;
z-index:-1;
left: 0;
top: 0;
width: '100%';
height: '100%';
}

Related

Make second container stick on top right after the first one when scrolling

As you can see here : http://www.shadownet.com.mv/products-2/
The first container sticks on top when scrolled vertically from the container. It should end and the second container "SHADOW SERVER SERIES" should stick on top replacing the first one (bringing the first one to the original position) when it is scrolled vertically from the container.
Right now i use this JS code to make the first one stick but when i use it for the second one, it sticks both on top and doesn't give the intended results :
var menu = document.querySelector('#sticky')
var menuPosition = menu.getBoundingClientRect().top;
window.addEventListener('scroll', function() {
if (window.pageYOffset >= menuPosition) {
menu.style.position = 'fixed';
menu.style.top = '42px';
menu.style.width = '100%';
} else {
menu.style.position = 'static';
menu.style.top = '';
}
});
I apologize for my bad english, im not a native speaker.
If you can use CSS, I would use the menuPosition as state in CSS.
So first the JS function would control state:
var menu = document.querySelector('#sticky'),
menuPosition = menu.getBoundingClientRect().top;
window.addEventListener('scroll', function() {
if (window.pageYOffset >= menuPosition){
document.body.classList.add('scrolled');
} else {
document.body.classList.remove('scrolled');
}
});
I've used classList which has a polyfill.
As Obsidian Age pointed out, move the variable menuPosition inside the event controller when it's CSS is dynamic from the top.
Then in CSS, use the body state to control offset for both containers:
#sticky { display: none; position: static; top: 48px; /*...*/ }
#sticky + #sticky2 { display: none; position: static; width: 100%;/*...*/ }
.scrolled #sticky { display: block; position: fixed; }
.scrolled #sticky + #sticky2 { display: block; position: fixed; }
The + in CSS only works if both containers are direct children of the same parent.
For this particular one,
I used stickyJS which worked wonderfully and out of the box. I was using a wordpress website. I added the script to header.php and added the JS snippet on desired page, set IDs for the two containers and gave z-index so that they go above each other when in view.

Append(ajax -data) outside screen (left:100%;)

I'm trying to create a slider of posts. I charge the data using ajax and then I apply append to inject the content to a div (id=ajaxinserted1). But I don't want to add this data into screen. I want that data to be added outside of screen (left:100%), so then I can apply a CSS transition to get it on screen with a slide animation effect.
How could I append(data) into the DOM outside the screen?
Thanks
The below code should dynamically calculate the offset based on the width of the images returned from the request. The explanation is in-line. This also required the container to be positioned absolutely.
// Cache the element
var $container = $('.ajaxinserted1');
// Append the images to the container
$container.append(
'<img src="https://www.placehold.it/100">',
'<img src="https://www.placehold.it/100">',
'<img src="https://www.placehold.it/100">',
'<img src="https://www.placehold.it/100">'
)
// Store the offset value
var offsetLeft = 0;
// Loop over the images and update the offset value
$.each($container.children(), function(a, b) {
offsetLeft = offsetLeft - b.width;
})
// Set the offset for the container
$container.css('left', offsetLeft);
// Animation
$('.ajaxinserted1').animate({
left: "10px"
}, 500);
.ajaxinserted1 {
position: absolute;
}
.ajaxinserted1 img {
padding: 10px;
height: 100px;
width: 100px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="ajaxinserted1"></div>
If I understand your question correctly, you just want to append your post under the existing ones and style it so it appears off screen so it can then slide in. So maybe something like...
1) Append your new post HTML into the content div with a class on it called 'new-post'
2) With CSS for new-post class...
.new-post {
position:relative;
left:100%;
}
3) Do your CSS transition to slide it back on screen and remove the class once finished.
Notes:
You may need to set the left attribute in absolute pixels, e.g. 600px, it depends on the layout of your page and where you want it to slide in from.
You could consider using opacity:0 and doing a fade in transition as well

Changing image widths after page had loaded if width is declared already? If width is undeclared, width will change but not if declared as I have

The trouble is that I need these images with generated IDs "cam_snap_XXX" to become a different width if they are dragged and dropped into this area. I can make the height change but NOT THE WIDTH because the width is designated to 20px if x==1. Never is the image height specified therefore I believe that is the reason it is changeable? Q: How can I make these image widths change from 20px to 100px if "dragged"?
while (cnt <= 100) {
cam_icon=document.getElementById('cam_snap_' + cnt);
cam_icon.style.visibility = 'hidden';
if (x==1) {
cam_icon.style.width = '20px';
cam_icon.style.visibility = 'visible';
}
cnt++;
}
The height changes from the following javascript...
//js for adding class "dragged" which gives new height and width image parameters
$('.droparea td.drop').droppable({
onDrag: function (e, source) {
$(this).addClass('dragged'); //Changes height correctly not width though.
}
}
And the css..
//css for attempting to change image width and height on drop
.dragged{
height: 100px; //Works because height stretches image height from ~20px to 100px.
width: 100px; //**Doesn't work and is useless because width remains 20px.**
}
Should I try removing the class before adding class 'dragged' to these images? Using removeClass()? Any ideas are welcome even if not the solution.
This part of javascript modifies your HTML
cam_icon.style.width = '20px';
cam_icon.style.visibility = 'visible';
to
<someTag id="cam_snap_x" style="width:20px;visibility:visible">
According to css rules inline style (inside an HTML element) has the highest priority. so you'll have to change attribute value to see changes in UI.
Solution 1: change your onDrag function like below.
$('.droparea td.drop').droppable({
onDrag: function (e, source) {
$(this).width(100).height(100); //This will change the style property
}
}
Solution 2: Use !important to prioritize value specified in class over inline style attribute
.dragged{
height: 100px;
width: 100px !important;
}

Lightbox moves image to bottom right corner

I'm writing a lightbox image gallery and struggling with the correct image positioning.
When clicking on an image, the lightbox appears. It's a completely new object generated with JS. By setting the margins, I move it to the screen middle (with z-index).
But these actions are performed before the image got time for loading. So JS doesn't have the required information clientWidth and clientHeight and uses 0 instead. This effects that the top left image corner (which is before loading the same as the other corners as well) is in the middle of the screen.
When the image starts loading, it will be extended to the bottom right.
How do I position the image correctly on the screen?
PS: No connection to the lightbox/lightbox2 library.
PPS: relevant code:
JS:
function lightbox(res, dsc) {
// lbimg: Lightbox-Image
var lbimg = document.createElement("img");
lbimg.src = res;
lbimg.id = "lbimg";
document.body.insertBefore(lbimg, document.body.firstChild);
lbimg.style.marginTop = "-" + Math.floor(lbimg.clientHeight/2.) + "px";
lbimg.style.marginLeft = "-" + Math.floor(lbimg.clientWidth/2.) + "px";
}
CSS:
#lbimg {
max-width: 70%;
max-height: 80%;
position: absolute;
left: 50%;
top: 50%;
border: 10px solid #fff;
z-index : 10;
}
HTML (only miniature images are displayed):
<div class="list">
<div><a onclick="lightbox('image.JPG', ''); "><img class="mini" src="image.JPG_MINI.jpg" /></a></div>
<!--other images are defined analogous-->
</div>
function lightbox(res, dsc) {
var lbimg = document.createElement("img");
lbimg.id = "lbimg";
lbimg.onload = function() {
document.body.insertBefore(lbimg, document.body.firstChild);
lbimg.style.marginTop = "-" + Math.floor(lbimg.clientHeight/2) + "px";
lbimg.style.marginLeft = "-" + Math.floor(lbimg.clientWidth/2) + "px";
};
lbimg.src = res;
}
You have to wrap both the DOM insertion and style setting in a load handler (if you wrap only style changes, you will see element "shifting" after insertion). Also set your src after binding the load handler, otherwise it's possible Internet Explorer will miss the handler (when loading images from cache).
Try wrapping your margin calculations inside an onload call:
lbimg.onload = function () {
lbimg.style.marginTop = "-" + Math.floor(lbimg.clientHeight/2.) + "px";
lbimg.style.marginLeft = "-" + Math.floor(lbimg.clientWidth/2.) + "px";
};
This will ensure that the height and width are available to the JS in order that the margins can be calculated correctly.

My jquery loading overlay doesn't show up every

For whatever reason, my jquery loading overlay doesn't load at all under any circumstance even though the same code was working just days ago. Well, not the exact same code. I have been trying to get the overlay to resize with the window, and I have been trying different things, but I don't understand what I did that caused the overlay to never even show up? Here is the code that should attach to the overlay to the correct div...
function MRNSearchInternals()
{
//debugger;
var form = $("#MRNSearch");
$div = $("#TabView1");
var srlzdform = form.serialize();
var PopID = <% =PopID %>;
var options = [];
var $url = $("#target").attr("action");
$('<div id="overlay">').css({
position: 'absolute',
opacity: 0.2,
top : $div.offset().top,
left : $div.offset().left,
width : $div.offset().width,
height : $div.outerHeight(),
background: 'blue url(<%=Url.Content("~/images/ajax-loader.gif")%>) no-repeat center'
}).hide().appendTo($div);
$("#overlay").fadeIn();
$.post('<%:Url.Action("SearchByMRN", "PatientACO")%>', srlzdform, function (data)
{
DisplayDemographicSearch(data);
$("#overlay").fadeOut();
});
}
Notice how I create the div. I give it an id, and then I call it's css atribute. From there I set all the css attributes. I then attempt to call fadeIn, and fadeOut after the ajax call. Any body have any idea why this isn't working? Any help would be great.
Some More clarification
Also notice how I chose the div to overlay. I get a div id from my dom
$div = $("#TabView1");
Also, I looked the source, and I do have that particular div in there. So that is not the problem. Somehow or the other, it simply isn't showing up.
UPDATE: The DOM I get
Below is what is produced from the jquery code. It appears as though everything is being created fine. Note also, that display is set to none. That is what I would expect since I have the overlay fade out. My question is why does it never show up.
<div class="TabView" id="TabView1">
<div class="Tabs">...</Tabs>
<div class="Pages">
<div id="overlay" style="left: 114px; top: 205px; height: 452px; display: none; position: absolute; opacity: 0.2; background-image: url("/images/ajax-loader.gif"); background-attachment: scroll; background-repeat: no-repeat; background-position-x: center; background-position-y: center; background-size: auto; background-origin: padding-box; background-clip: border-box; background-color: blue;"/>
</div>
Well, the better way to create the overlay div would be
$('<div/>', {
id: 'overlay'
})
Does that solve the problem? Otherwise, the ID might not be created, or does it?
Update for the edit from your post: the "width" attribute is not set on the created overlay. What happens if that is added and set to e.g. 100px? It seems like there is something wrong with the setting of the width attribute (or the getting of the width attribute of $div).
Is this code called more than once? If so, are you removing #overlay somewhere?
Calling this code multiple times would create duplicate #overlay dom nodes which is a no-no and could explain why it doesn't work sometimes.
To remove it, change:
$("#overlay").fadeOut();
to:
$("#overlay").fadeOut('slow', function () {
$("#overlay").remove();
});
Your selector doesn't look right.
I would try:
$('#overlay').css. . . .
function MRNSearchInternals()
{
//debugger;
var form = $("#MRNSearch");
$div = $("#TabView1");
var srlzdform = form.serialize();
var PopID = <% =PopID %>;
var options = [];
var $url = $("#target").attr("action");
$('<div id="overlay">').css({
position: 'absolute',
opacity: 0.2,
top : $div.offset().top,
left : $div.offset().left,
width : $div.offset().width, //<- The problem is right here should be $div.width
height : $div.outerHeight(),
background: 'grey url(<%=Url.Content("~/images/ajax-loader.gif")%>) no-repeat center'
}).hide().appendTo($div);
$("#overlay").fadeIn();
$.post('<%:Url.Action("SearchByMRN", "PatientACO")%>', srlzdform, function (data)
{
DisplayDemographicSearch(data);
$("#overlay").fadeOut('slow', function () {
$("#overlay").remove();
});
});
}
Man. That was real hard to debugg. I wish Visual studio 2010 had better jquery debugging capability. Thankfully, the next version is supposed to be a better jquery debugger. But, the problem was the width attribute.

Categories