I have multiple JavaScript draggable DIV windows. When clicking a DIV, I want the window to get the highest z-index value. I've made a solution by adding/removing classes to the element in focus, BUT, I would like the windows to keep their "layer" -order (as if the entire DIV window node was re-appended to the DOM when being clicked).
Let's say there are five DIV's in the DOM. div1, div2, div3, div4 and div5. -div5 is closest to the front and div1 is in the back and so on.
When clicking div1, -div1 will get focus and put to front, setting div5 back one step. Then clicking div3, -div3 gets closest to front and div1 and div5 are put back one step like this: div2, div4, div5, div1, div3.
If you don't want to loop through all your divs and don't want to mess up with z-index you can just append again that div to the parent element (the body?) before dragging.
function stepUpNode(elementDragged){
var parentNode = elementDragged.parentNode;
parentNode.appendChild(elementDragged);
}
If you'd like to do this without re-appending the element, my solution when I wrote something similar a while back was to keep track of the maximum z-index. Every time a window is brought forward, the maximum z-index is incremented and the element's z-index is set to the new value. Of course, if someone messes with the windows enough, they might end up having very large z-index values, so this isn't always the best solution.
var maximumZIndex = 1;
var bringForward = function (element) {
maximumZIndex += 1;
element.style.zIndex = maximumZIndex;
}
The first and most likely easiest approach: simply increase the maximum z-index every time a div gets selected. Since the z-index value can become pretty large (2147483647 if I remember correctly) you most likely will never run out of levels...
The following snippets use some jQuery:
var frontmostWindow = null;
var topZIndex = 10;
$('div').click(function() {
if (this != frontmostWindow) {
frontmostWindow = this;
topZIndex++;
$(this).css('zLevel', topZIndex);
// anything else needed to acticate your div
// ...
}
});
If you have restrictions on the z-indices you can use, you will need to re-assign levels every time a different div gets selected, e.g. like this:
// store z-index-ordered divs in an array
var divs = $('div').toArray().sort(function(a, b) {
return parseInt($(a).css('zIndex'), 10) - parseInt($(b).css('zIndex'), 10);
});
// store available z-indices
var zIndices = [];
for (var i = 0; i < divs.length; ++i) {
zIndices.push($(divs[i]).css('zIndex'));
}
// Event listener for clicks
$('div').click(function() {
alert("heyya " + this.id);
var element = this;
var index = divs.indexOf(element);
// check if clicked element is not already the frontmost
if (index < divs.length - 1) {
// remove div from array and insert again at end
divs.splice(index, 1);
divs.push(this);
// re-assign stored z-indices for new div order
for (var i = 0; i < divs.length; ++i) {
$(divs[i]).css('zIndex', zIndices[i]);
}
// anything else needed to acticate your div
// ...
}
});
Related
I have owl carousel slider with 5 items. And my problem is that i need first and last element of my slider to be always with opacity. Slider has like 15 elements which 9 cloned, 5 have .active class and one with cloned and .active.
I tryied make it using javascript where i found all ".active" classes in slider, but i don't exactly know what i should do with object which was found.
There is code which found all ".active" classes
var owlCarouselActive = document.getElementById("slider-tour").getElementsByClassName("owl-item active");
I need in order to this .active first and last have :before with my background style when i click on button prev or next.
You could do this with javascript
var owlCarouselActive = document.getElementsByClassName("owl-item active");
var first = owlCarouselActive[0]; //get first item
var last = owlCarouselActive[owlCarouselActive.length - 1]; //get last item
first.style.opacity = 0.8;
last.style.opacity = 0.8;
I'm not at home but try something like this:
function setOpacity() {
var elements = $('.active');
let count = 0;
$(elements).each(function(k,v) {
if (count == 0 || count == elements.length - 1) {
$(v).css('opacity', '0.8');
}
count++;
});
}
$(document).ready(function() {
setOpacity();
});
Run that function everytime you want it to update.
E.G on a button click.
You can use owlCarouselActive [0] to access the first element and owlCarouselActive [owlCarouselActive.length-1] to access the last element. Generally you can access i-th element by owlCarouselActive [i].
I'm puzzled by the function of my JavaScript image slider since it changes the slide only once upon clicking next (I haven't worked on previous yet, but should be logical enough to re-adjust). The code is given by:
$(".room_mdts").click(function(event){
//get the target
var target = event.currentTarget;
var room = $(target).data("room");
currentIndex = parseInt($(target).attr('data-room'));
//First way, by reuse target (only inside this function)
$('#room_details_holder').show();
//The second, by using selectors
//remove all "selected" classes to all which have both "room" and "selected" classes
$('.room_exp.selected').removeClass("selected");
//add "selected" class to the current room (the selector can also be the target variable)
$('.room_exp[data-room='+room+']').addClass("selected");
});
var currentIndex = 0;
var adjIndex = currentIndex - 1,
items = $('.room_details .room_exp'),
itemAmt = items.length;
function cycleItems() {
var item = $('.room_details .room_exp').eq(currentIndex);
items.hide();
item.css('display','inline-block');
}
$('.room_next').click(function() {
adjIndex += 1;
if (adjIndex > itemAmt - 1) {
adjIndex = 0;
}
cycleItems(adjIndex);
cycleItems(currentIndex);
$('#room_name').text($('.room_exp:nth-child('+(adjIndex+2)+')').attr('title'));
});
$('.room_previous').click(function() {
currentIndex -= 1;
if (currentIndex < 0) {
currentIndex = itemAmt - 1;
}
cycleItems(currentIndex);
$('#room_name').text($('.room_exp:nth-child('+(currentIndex+1)+')').attr('title'));
});
$('#room_name').text($('[style*="inline-block"].room_exp').attr('title'));
});
The reason I had to introduce adjIndex is because without '-1' the slide changed by 2 on the first click, again, no idea why.
The Fiddle: https://jsfiddle.net/80em4drd/2/
Any ideas how to fix that it only changes once? (And also, the #room_name only shows after the click, does not show upon expanding).
Try this I rearranged your code a little bit:
made your currentIndex global and assigned with the adjIndex. If that's ok I will improve my answer:
If you click on the right arrow it goes to the end and comes back to the beginning.
url: https://jsfiddle.net/eugensunic/80em4drd/3
code:
function cycleItems() {
currentIndex=adjIndex;
var item = $('.room_details .room_exp').eq(currentIndex);
items.hide();
item.css('display','inline-block');
}
Okay, great thanks to eugen sunic for the little push that got me thinking!
I have finially cracked all of the pieces, although, I might have some extra unecessary bits of code, duplicates etc, but the functionallity is just perfect!
What I have edited:
I moved one of the closing brackets for the cycleFunction () closing bracket to the end of .click functions, that is to make the variable global (at least for those 3 functions)
I changed the title writing function from: $('#room_name').text($('[style*="inline-block"].room_exp').attr('title'));
to:$('#room_name').text($('.room_exp:nth-child('+(adjIndex+2)+')').attr('title'));
Added a few changes regarding .addClass/.removeClass to the $('.room_details_close').click(function(){.
Now, openning any of the thumbnails shows the title immediately (the right title), clicking '<<' or '>>' changes the slide to next and previous, respectively, while the title changes accordingly. Closing the expanded menu and clicking on a different thumbnail results in re-writing the currentIndex (hence, adjIndex too), so the function starts again with no problem.
Please feel free to use!
The new fiddle is: Fiddle
I'm trying to pin some divs in place and fade them in and out as a user scrolls down. My code looks like this so far:
$(window).on("load",function() {
var fadeDuration = 500;
function fade() {
// compute current window boundaries
var windowTop = $(window).scrollTop(),
windowBottom = windowTop + $(window).innerHeight(),
focusElt = null;
// find our focus element, the first visible .copy element,
// with a short-circuiting loop
$('.imgdiv').toArray().some(function(e, i) {
var objectTop = $(e).offset().top;
if ((objectTop >= windowTop) && (objectTop <= windowBottom)) {
focusElt = e;
return true;
}
console.log(focusElt);
});
// obscure all others
$('.focus').not(focusElt)
.removeClass('focus')
.fadeTo(fadeDuration, 0);
// focus on our focus element; if was the previous focus, nothing
// to do; but if it wasn't focus / wasn't showing before, make
// it visible and have class focus
$(focusElt).not('.focus')
.addClass('focus')
.fadeTo(fadeDuration, 1);
}
fade(); //Fade in completely visible elements during page-load
$(window).scroll(function() {fade();}); //Fade in elements during scroll
});
Here's the corresponding fiddle that almost does what I'm looking for, but instead of the green "Fade In" blocks moving upward and fading, I want them pined in place near the top of the window. As the "IMG DIVs" move past them they will fade and reappear with each new "IMG DIV". Here, I'm focusing on the particular green block and fading it when it becomes the focus element. Instead, what I need to do is, focus on the IMG DIV blocks, add a "pinned" class to the green blocks when they reach the top of the page, and fade the green blocks in and out.
Does anyone have any advice?
Part 2 of my question is how to do this with native JavaScript, and not rely on jQuery's dependency.
Ok, so lets split your first issue into two issues :)
First of all, you want to (in general) do something when some element becomes visible in the viewport and when it becomes invisible. So, basically, all you need is function like that:
watchElementIsInViewport(
$('.imgdiv'),
doSomethingWhenElementAppearedInViewport,
doSomethingWhenElementOutOfViewport
);
You know, that when element becomes visible, you want to show some other element. When element becomes invisible, you want to hide that related element. So now, define those two functions:
function doSomethingWhenElementAppearedInViewport(element) {
// retrieve text related with the element
var $copy = $(element).next('.copy');
// fade it in
$copy.fadeTo(500, 1);
}
function doSomethingWhenElementGotOutOfViewport(element) {
// retrieve text related with the element
var $copy = $(element).next('.copy');
// fade it out
$copy.fadeTo(500, 0);
}
What about watchElementIsInViewport? There is no magic inside, only logic you already created, but decoupled from showing of finding elements.
function watchElementIsInViewport($elements, elementAppearedInViewport, elementGotOutOfViewport) {
var currentlyVisible = [ ];
// retrieve positions once, assume it won't change during script is working
var positions = getVerticalBoundaries($elements);
function _scrollHandler() {
var viewportTop = window.scrollY;
var viewportBottom = viewportTop + window.innerHeight;
$elements.each(function(index, element) {
var elementPosition = positions[index];
/* if you wish to check if WHOLE element is in viewport
* var elementIsInViewport = (elementPosition.top >= viewportTop) &&
* (elementPosition.bottom <= viewportBottom);
*/
var elementIsInViewport = (elementPosition.top < viewportBottom) &&
(elementPosition.bottom > viewportTop);
var elementIndexInCurrentlyVisible = currentlyVisible.indexOf(element);
// if element is visible but was not visible before
if(elementIsInViewport && (elementIndexInCurrentlyVisible === -1)) {
elementAppearedInViewport(element);
currentlyVisible.push(element);
// if element is not visible but was visible before
} else if(!elementIsInViewport && (elementIndexInCurrentlyVisible !== -1)) {
elementGotOutOfViewport(element);
currentlyVisible.splice(elementIndexInCurrentlyVisible, 1);
}
});
}
// initial check & update
_scrollHandler();
// check & update on every scroll
$(window).on('scroll', _scrollHandler);
}
And that's all. Working example.
I am absolutely new to javascript, so please bear with me.
I have 50 elements on my page with ids. All are set to visibility:hidden and position:fixed. I have a button that corresponds to each element. When a button is clicked, a javascript function is initiated which makes the corresponding element visibile and position:relative. Code looks something like this:
document.getElementById("id1").style.position='relative';
document.getElementById("id1").style.visibility='visible';
To ensure that only one element is ever visible and relative, I also need to make the other 49 elements hidden and fixed. How can I accomplish this without having to resort to the following sort of code:
function makeid1visibile()
{
document.getElementById("id1").style.position='relative';
document.getElementById("id1").style.visibility='visible';
document.getElementById("id2").style.position='fixed';
document.getElementById("id2").style.visibility='hidden';
document.getElementById("id3").style.position='fixed';
document.getElementById("id3").style.visibility='hidden';
document.getElementById("id4").style.position='fixed';
document.getElementById("id4").style.visibility='hidden';
// etc...
}
Any help would be appreciated, because with 50 elements, the number of lines of coding would be outrageous.
Should be able to handle it with a single loop, just pass in the number of the item you wish to show:
function makeIdVisible(id) {
document.getElementById("id" + id).style.position='relative';
document.getElementById("id" + id).style.visibility='visible';
for (var i = 1; i <= 50; i++) {
if (i !== id) {
document.getElementById("id" + i).style.position='fixed';
document.getElementById("id" + i).style.visibility='hidden';
}
}
}
give yours checkboxes classname "someclass" and select all elements by function documet.getElementsByClassName
You can write a function like this:
function makeVisible( id ){
var idList = ['id1','id2','id3','id4'];
for( var i = 0, l = idList.length; i<l ; i++ ){
document.getElementById(idList[i]).style.position='fixed';
document.getElementById(idList[i]).style.visibility='hidden';
}
document.getElementById(id).style.position='relative';
document.getElementById(id).style.visibility='visible';
}
Then you can use
makeVisible('#id1');
to make the id1 element visible
I have the following function:
function slideDown() {
//get the element to slide
sliding = document.getElementById('slideDiv1');
//add 1px to the height each time
sliding.style.height = parseInt(sliding.style.height)+1+'px';
t = setTimeout(slideDown,30);
if (sliding.style.height == "401px") {
clearTimeout(t);
}
}
which is called within this function:
function addDiv(nextImageSlide) {
//finds the src attribute of the image nested in the Li
elemChild = nextImageSlide.firstChild;
imageSrc = elemChild.getAttribute('src');
//loops and creates six divs which will be the slices. adds background property etc
for (i = 0, j = 0, k = 1; i< = 19; i++, j++, k++) {
var newDiv = document.createElement('div');
newDiv.setAttribute('class', 'new-div');
newDiv.id='slideDiv' + k;
newDiv.style.height = '1px';
newDiv.style.background = 'url(' + imageSrc +') scroll no-repeat - '+39.5 * j + 'px 0';
var a = document.getElementById('content');
a.appendChild(newDiv);
}
slideDown();
}
Which is called within another function that defines nextImageSlide. It later removes all the divs that it just made.
The idea is for an image gallery. When the user hits the next button, I want slices of the next image to slide down to show the next image. Those slices are then taken away and the new image revealed.
I would like something like this: http://workshop.rs/projects/jqfancytransitions/.
It's for an assignment so we have to write all the code ourself and this is the best way I can think to replicate it. The only problem is that I keep getting an error:
'sliding is null. sliding.style.height = parseInt(sliding.style.height)+1+'px';'
No matter what I do I can't get rid of it. The thing is if I define sliding as a totally different id, (for example I made a random little div outside of everything), it working.
This error shows when I try to access the divs, it just made that it throws a hissy fit.
Anyone see any errors in my code?
Hopefully this is just a typo while pasting into the site here, but:
car a = document.getElementById('content');
^---syntax error, which'll kill your entire script - var?