Div dissappears when Dragging from one div to another with scroll overflow using jquery - javascript

I have two "DIV"s, one on the left and one on the right. The right one has draggable elements and the left one has a droppable container. Both DIV's have the CSS attribute overflow: auto, which is essential in my implementation because I need a scroll to appear in each div when either DIV overflows.
The issue is, when I drag the element in the right DIV, and move it to the left, it disappears after the edge of the DIV.
This is a sample of what I'm trying to do.
<!DOCTYPE html>
<html>
<head>
<title>Practice</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<script>
$(function() {
for (var i = 1; i <= 20; i++) {
$('#right').append($('<div></div>')
.addClass('item')
.html(i));
}
$(".item").draggable({
cursor: "move",
revert: "invalid"
});
$("#bin").droppable({
drop: function(event, ui) {
var mydiv = $(ui.draggable);
$("#bin").html("Dropped");
}
});
});
</script>
<style>
#left {
border: 2px solid black;
position: fixed;
width: 49%;
height: 98%;
overflow: auto;
}
#right {
border: 2px solid black;
position: fixed;
left: 52%;
top: 2%;
width: 46%;
height: 98%;
overflow: auto;
}
#bin {
border: 2px solid black;
position: relative;
left: 12%;
top: 5%;
width: 75%;
height: 75%;
}
.item {
border: 2px solid black;
left: 12%;
top: 5%;
width: 15%;
height: 5%;
}
</style>
</head>
<body>
<div id="left">
<div id="bin">
</div>
</div>
<div id="right">
</div>
</body>
</html>

You need to remove the overflow:auto in your CSS. You will then see the item will be visible when dragging between the divs then.
In order to accomplish the functionality you'd like, you need an outer div wrapping the two container boxes. You'd set an fixed height on the outer div, then use overflow-y:scroll to get your functionality.

You can do as others have suggested, but I've always found the best way to accomplish this is to set the draggable item to position:fixed
see for example:
https://jsfiddle.net/gregborbonus/tzz0927p/1/
For me personally, this allowed a lot more flexibility, but I also did a lot of work with responsive designs and such to make it work right.
I've edited to include overlapping div's. Added a few functions to make it more visible, like random Color, and an on hover and hover out event to make it possible to see and click each box.
https://jsfiddle.net/gregborbonus/tzz0927p/3/
With 100 and added a scroll function to make the scroll smooth. Also added a quick snippet so that the elements would only appear within the containing box.
This is different from your code, it uses 2 containers, rightc for the main container(the one that scrolls) and right for the container of all the elements. The rest is commented in the code.
https://jsfiddle.net/gregborbonus/tzz0927p/13/
so, something I realized was that the elements would still overlap the page on page load.
So, to show this working with an even shorter div and changed to compensate for onload:
https://jsfiddle.net/gregborbonus/tzz0927p/15/

Related

Move relative object position when scrollbar appears using CSS

On my page, I'm displaying a log file in a div element with overflow-y:auto. In the top right corner of the div, I'm overlaying a close button div with position:relative.
When the scrollbar appears, the button is overlaying the scrollbar which is hard to see and looks ugly. You can see an example here: https://jsfiddle.net/4azw0rLf/
Moving it with javascript when scrollHeight exceeds clientHeight feels like a hack. Is there an option in CSS to move the close button to the left for the width of the scrollbar as soon as it appears?
You can wrap your terminal and move your close button inside. I created a minimal example starting from your code.
EDIT
With the first answer the close button scrolled along with the text, I corrected using the position: sticky; and top:0px;
It is not compatible with all browsers, but with most, you can check compatibility here.
const terminal = document.getElementById("terminal");
addText = () => {
terminal.innerHTML += "overflowing line<br>";
}
#container-terminal {
position: relative;
overflow-y: auto;
border: 2px solid;
height: 100px;
width: 200px;
}
#terminal {
position: absolute;
height: 100%;
width: 100%;
}
#closeBtn {
background-color: red;
position: -webkit-sticky;
position: sticky;
top:0px;
width: 20px;
display: inline-block;
float: right;
}
<div onclick="addText()" style="cursor:pointer;">Click to add text</div><br>
<div id="container-terminal">
<div id="terminal">CSS only<br>CSS only<br>CSS only<br>CSS only<br>CSS only<br></div>
<div id="closeBtn">X</div>
</div>

Changing the order in which <div>'s overlap each other with jQuery mouse-click events

I'm trying to make specified div's on my page interactive and thus, change focus (come to the foreground if you will) when clicked. Essentially, I would like the div's to act much like the windows do on a computer running Microsoft Windows.
This is what I've come up with so far using z-index and it does work, sort of. The problem is that the div's appear to have their own "order" so to speak when it comes to overlapping each other based on where they are placed in the HTML.
For instance, if you click "Div2" then "Div1", you can see that "Div2" ends up actually going back behind "Div3" rather than staying in front of it as it previously was. I'd like order to be retained as clicked. If you click Div2, it should be in the front, then you click Div1 and it would then be in front of Div2, etc.
Any ideas on a way around this would be greatly appreciated. Thank you in advance!
// Global vars
var lastFocused;
// When left mousedown on a ".window" element, remove the ".window-focus" class from id
// specified in the global var "lastFocused". Next, update the global var "lastFocused"
// with the most recently clicked element id. Lastly, add the ".window-focus" class to
// the id specified in global var "lastFocused".
$('.window').mousedown(function () {
$(lastFocused).removeClass('window-focus');
lastFocused = "#" + $(this).attr("id");
$(lastFocused).addClass('window-focus');
});
// Make all ".window" elements resizable and draggable.
$('.window').draggable({containment: '#container'}).resizable({containment: '#container'});
html, body, #container {
height: 100%;
width: 100%;
font-family: Roboto;
background-color: #333;
color: #c9c9c9;
font-size: 1em;
overflow: hidden;
}
.window {
position: absolute !important;
border: 1px solid #999;
background-color: #222;
height: 100px;
width: 100px;
z-index: 1;
}
#div1 { top: 20px; left: 20px; }
#div2 { top: 60px; left: 60px; }
#div3 { top: 100px; left: 100px; }
.window-focus { z-index: 2; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<div class="window" id="div1">ONE</div>
<div class="window" id="div2">TWO</div>
<div class="window" id="div3">THREE</div>
Your issue is that you are always giving the the currently clicked div a z-index of 2, which does bring it to the front, but then when you remove that class from an element it simply goes back to it's original z-index. You need that last-applied z-index not to change and have the next-clicked element get a z-index that is one higher than the previous one.
Just keep track of the last z-index assigned to the last-clicked div element and increment it by one after each assignment so that the next clicked element will get a higher z-index assigned to it.
NOTES:
There is no need for the lastFocused variable, the .window-focus
CSS selector, or to assign a z-index:1 to the .window elements.
You were exactly right about elements having an implicit z-index
based on where they are in the HTML. For sibling elements, the z-index is simply based on the sequence. The earlier in the sequence, the lower the z-index. But, it's more complex when you start working with elements that don't share the same parent. See the stacking context for details.
JQuery recommends using the element.on("eventName", callback)
method rather than event-specific methods (i.e.
element.mousedown(callback)).
It's probably not a good idea to use a class name of .window for
elements that are not the window object. It will cause confusion. For something like this, a class name of stackable or draggable seems appropriate.
var highestZ = 3; // There are 3 divs, so highest z-index in use is initially 3
// When any of the div.stackable elements get clicked...
$('.stackable').on("mousedown", function () {
$(this).css('z-index', ++highestZ); // Clicked div gets a z-index one higher than prevous highest
});
// Make all ".stackable" elements resizable and draggable.
$('.stackable').draggable({containment: '#container'}).resizable({containment: '#container'});
html, body, #container {
height: 100%;
width: 100%;
font-family: Roboto;
background-color: #333;
color: #c9c9c9;
font-size: 1em;
overflow: hidden;
}
.stackable {
position: absolute !important;
border: 1px solid #999;
background-color: #222;
height: 100px;
width: 100px;
user-select:none;
cursor:pointer;
}
#div1 { top: 20px; left: 20px; }
#div2 { top: 60px; left: 60px; }
#div3 { top: 100px; left: 100px; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<div class="stackable" id="div1">ONE</div>
<div class="stackable" id="div2">TWO</div>
<div class="stackable" id="div3">THREE</div>

Hide element "beneath" div of lower z-index

Two fiddles. The first, showing everything working as I want: http://jsfiddle.net/3SWwD
The second, showing the problem as it exists on the site I'm trying to deploy the effect on: http://jsfiddle.net/3SWwD/1/
Those fiddles describe everything this code does, but for thoroughness:
I have two container divs bumped up to one another, the first of which contains an imagel which I have simplified to <div id="image"> for this example.
<div id="container">
<div id="image"></div>
</div>
<div id="never_cover_me">
</div>
They are styled as follows, and theses styles will exhibit the issue, which I'll explain when I show the js.
#container{
height: 400px;
width: 400px;
background: blue;
position: relative;
z-index: 200;
}
#image{
height: 200px;
width: 200px;
background: red;
position: relative;
top: 200px;
left: 100px;
z-index: 50;
}
#never_cover_me {
position: relative;
height: 400px;
width: 400px;
background: yellow;
z-index: 100;
}
Lastly, some Jquery/JS moves the image down, thus into the space of #never_cover_me. If all was well in the world, #image would be covered by #never_cover_me while it was moved down, but since #container has a higher z-index than #never_cover_me, obviously that isn't the case and the image is instead drawn over #never_cover_me.
$(document).ready(function(){
setInterval(
function(){
$('#image').animate({top: '+=200px'}, "slow", function(){
$('#image').delay(1000).animate({top: '-=200px'}, "slow")
});
},3000
);
});
For various reasons, #container MUST have a higher z-index than #never_cover_me. Semantically, I would prefer if #image stays within #container.
Ideas?
The #container:
z-index: 200;
is above #never_cover_me:
z-index: 100;
Therefore, it is causing the issue you are experiencing. Here is more information on stacking order and how descendants are affected.
https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/Stacking_and_float
You shouldn't really try to use other elements to hide your content. A better solution would be to set overflow:hidden; on #container because the effect you are going for is "hide this when the block is outside the current element."
It was as easy as adding overflow:hidden to #container.
Fiddle: http://jsfiddle.net/3SWwD/2/

Hide scroll bar of nested div, but still make it scrollable [duplicate]

This question already has answers here:
Hide scroll bar, but while still being able to scroll
(42 answers)
Closed 8 years ago.
This is a reference that I used, which explains how to make a div scrollable with its scroll bar hidden. The only difference is that I have nested divs. Check my fiddle
HTML:
<div id="main">
<div id="sub-main">
<div id="content">
<div id="item-container">
<div class="item">a</div>
<div class="item">b</div>
<div class="item">c</div>
</div>
</div>
</div>
</div>
CSS:
#main {
width: 500px;
height: 500px;
}
#sub-main {
width: 500px;
height: 500px;
overflow: hidden;
}
#content {
background-color: red;
width: 500px;
height: 500px;
overflow: auto;
}
#item-container {
width: 1500px;
height: 500px;
}
.item {
width: 500px;
height: 500px;
font-size: 25em;
text-align: center;
float: left;
}
Like above, I have a overflowed horizontal div and I want to hide its scroll bar. I have to make it still scrollable because $.scrollTo() wouldn't work otherwise.
UPDATE:
I have read all the answers, but I still have not resolved my problem and don't know what's causing it. This is the live that's having troubles.
Basically, I am trying to follow this almost exactly the same, but there must be some reason that my website isn't working as expected. There are two problems.
When I set overflow: hidden to a parent container of scrollable items, I cannot scroll (native javascript scroll functions do not work too).
I want to scroll just the overflowed container, not the entire window. This can be done by setting a target in $.localScroll({ target: '#projects-content' }) but nothing scrolls when I set the target. If I don't, scrolling works as long as overflow:hidden is not applied.
Again, any help would be greatly appreciated.
HTML:
<div id="projects"> <!-- start of entire projects page -->
<div id="project-sidebar">
<a href="#project-first">
<div class="sidebar-item sidebar-first">first</div>
</a>
<a href="#project-second">
<div class="sidebar-item sidebar-second">second</div>
</a>
<a href="#">
<div class="sidebar-item sidebar-third">third</div>
</a>
</div>
<div id="project-content"> <!-- this must be the scrollable itmes' container, not the entire window -->
<div id="project-first" class="project-item">
<!-- these items should be scrollable -->
<div class="project-subitem" id="first-sub1">
<a href='#first-sub2' class='next'>next</a>
</div>
<div class='project-subitem' id='first-sub2'>
<a href='#first-sub1' class='prev'>prev</a>
</div>
<!-- end of scrollable items -->
</div>
</div> <!-- end of scroll scroll container -->
</div> <!-- end of entire projects page -->
<script>
// FIXME: when I set target, nothing scrolls.
// But I don't want the entire window to scroll
$('#projects').localScroll({
//target: '#project-content',
hash: false
});
</script>
CSS
#project-content {
width: 80%;
height: 100%;
position: relative;
float: left;
}
#project-sidebar {
float: left;
width: 20%;
height: 100%;
}
.project-item {
width: 300%;
height: 100%;
}
.project-subitem {
height: 100%;
width: 33.33%;
position: relative;
float: left;
}
Update:
After I added overflow:scroll to #project-content, the scrolling works as expected. All I need now is making scroll bars disappear in #project-content. I tried adding overflow:hidden to its parent but had no success. I also tried adding it to html, body, but then the entire document refuses to accept any scrolling functions like scrollTop().
Any help will be greatly appreciated!
Theory :
The technique is to use a parent container that is shorter than the child element with scrollbar. This image shows what I mean :
Practice :
In your case, I suggest using absolute positionning and negative bottom value on #project-content so it overflows it's parent container (#projects) at the bottom.
The point is now what negative value? It should be the same value as the with of a scroll but scrollbars are never the same width according to browsers. So I suggest giving a bigger value : -30pxto be sure it is hidden. You will just need to be carefull that you don't have content to close to the bottom that can be hidden on browesers with thin scrollbars.
This is the CSS you should add to your website :
#projects{
position: relative;
}
#project-content{
position: absolute;
top: 0;
left: 20%;
bottom: -30px;
/* remove:
height: 100%;
position: relative;
float: left;
padding-bottom: -15px
/*
}
scollbars take up around 20px so just make you scrollable div 20px taller and 20px wider and your scrollbars will be hidden:
#content {
background-color: red;
width: 520px;
height: 520px;
overflow: auto;
}
Example
It's kind of cheating but could you hide it behind the #content like this DEMO
#content {
background-color: red;
width: 500px;
height: 480px;
overflow: hidden;
}
#item-container {
width: 1500px;
height: 500px;
overflow: scroll;
}
If you know all containers that can be scrollable, you can hide scrollbar with CSS and a little bit of JS. For webkit-based browsers (safari, google chrome, opera) it will be CSS-only solution to set scrollbar width to 0. For IE, Firefox and other non-webkit browsers you should calculate scrollbar width that will be used as negative margin-right for you scrollable content.
To do so you should wrap your content into div with overflow-y:scroll to always show vertical scrollbar and hide this scrollbar with margin-right:-17px and parent overflow:hidden. Example is here. No need to set fixed width, nor height.
This is the way that used in jQuery Scrollbar. Hiding horizontal scrollbar is more complicated and requires to handle content changes to recalculate container height.
I basicly add padding:0 1em 1em 0; to the element where it is supposed to be hidden , this hides both scrollbars if parent has overflow: hidden. tune padding-bottom or only padding-right, if it is to hide only one of them.
1em is average width of scroll bars in most browsers :
http://jsfiddle.net/5GCsJ/912/
The solution to make the content itself with horizontal scroll.
Just increase the height of #main, and #content.
#main {
width: 500px;
height: 520px;
}
#sub-main {
overflow: hidden;
}
#content {
background-color: red;
width: 500px;
height: 520px;
overflow: auto;
}
#item-container {
width: 1500px;
height: 500px;
overflow: hidden;
}
.item {
width: 500px;
height: 500px;
font-size: 25em;
text-align: center;
float: left;
}
Use a script to create custom scrollbars.
http://manos.malihu.gr/jquery-custom-content-scroller/
Then use CSS(or modify script or change script config) to hide the custom scrollbars.
I did this crudely using jQuery and your example
Check this fiddle:
I simply detected the direction of the scroll-wheel and pushed the horiz-scroll bar with jQuery
$(document).ready(function(){
$('#content').bind('mousewheel', function(e){
var curScroll = $("#content").scrollLeft();
if(e.originalEvent.wheelDelta > 0) {
$("#content").scrollLeft(curScroll-500);
} else {
$("#content").scrollLeft(curScroll+500);
}
});
});
It is "crude" because I hard-coded some values like the 500px amount to scroll, you could write some more javascript to detect dynamically how much to scroll. Plus I don't know if the wheelDelta value will be +120 for up and -120 for down, for you and other users.
Also note that the scrolLeft() can be animated.. for smoother transitions.

Prevent scrolling past a certain point

I am trying to make a scrolling carousel, unlike other carousels this one doesn't jump from slide to slide but only allows the user to slowly move through them horizontally at a rate of 50px.
http://codepen.io/anon/pen/pyLfz
Problem is when clicking next, once the number 6 box comes into full view the script should not allow the user to go any further, same for when the number 1 box is in full view and prev link is clicked, the user should not be allowed to scroll back anymore.
Right now I can't figure out how to do that.
HTML:
<div class="carousel">
<div class="slide">
<article class="pod">1</article>
<article class="pod">2</article>
<article class="pod">3</article>
<article class="pod">4</article>
<article class="pod">5</article>
<article class="pod">6</article>
</div>
</div>
Prev
Next
CSS:
.carousel {
position: relative;
border: 1px solid red;
width: 250px;
height: 100px;
overflow: hidden;
}
.carousel .slide {
overflow: hidden;
position: absolute;
width: 600px;
}
.carousel .slide .pod {
width: 100px;
height: 100px;
line-height: 100px;
text-align: center;
background: blue;
box-shadow: 0 0 18px white;
color: #fff;
float: left;
}
jQuery:
$('.next').on('click', function() {
$('.slide').animate({
left: '-=50'
});
});
$('.prev').on('click', function() {
$('.slide').animate({
left: '+=50'
});
});
Your .carousel class need to have the same width at your .pod because you have the .carousel acting as a viewport. Also, change 50px to 100px for your .animate().
Here is my version with the changes suggested:
http://codepen.io/anon/pen/hcewq
EDIT
Sorry. I put the 50px offsets back. I have boundary checks as before but the issue issue is the clicking versus the timing of the animation. So, you need to check if your slider is going past its boundaries and have an animation flag check to see if the previous animation is complete or it will not get the latest offsets.
Here is the update: http://codepen.io/anon/pen/KJBzy
You need to use some math to determine if you're at the end or not.
Here is your pen, forked: http://codepen.io/chrisrockwell/pen/dxqbp
The main part is in the if statement for your next action:
if (Math.abs(slideOffset.left) <= ($slide.width() - $('.carousel').width() - moveBy)) {
$slide.animate({
left: next
});
}
With this structure you are able to easily add .pod's because, in your CSS, you can give .slide a ridiculously large width (10000em, for example) and it will still work. You can also change the width of the .pod's without having to modify anything but the CSS. Finally, you can change the amount it moves by, should you ever need to, by changing just one variable.
To cover all scenarios, you would need to add in more checks, but this should get you started.

Categories