In the following code I have:
Currently my code doesn't work as expected where the last active element is bought to the front. I am trying to create an extensible solution where there can be about five or so more buttons later with different content.
Also, is there a way to let the divs pop up near to the buttons that they are shown from? If I drag the button before I clicked it, the distance is a bit big.
My current attempt looks like this:
$(function() { /* Combine on ready logic into one place */ $("#button-one").draggable({ stack: 'div', containment: "body" }); $("#content-one").draggable({ stack: 'div', containment: "body" }); /* Hide all trip elements except for first */ $('.trip', '#content-one').not(':first').hide(); }); $('#button-one').on('mouseup', function() { if (!$(this).hasClass('ui-draggable-dragging')) { $("#content-one").toggle(); } }); $('#content-one').on('mouseup', function() { /* Reuse same logic in #button mouseup handler */ if (!$(this).hasClass('ui-draggable-dragging')) { /* If content element if not dragging, treat mouse up as conclusion of click event and rotate visibility of trip elements like this */ let trip = $('.trip:visible', '#content-one'); let next = trip.next().length === 0 ? $('.trip:first', '#content-one') : trip.next(); trip.hide(); next.show(); } }); $(function() { $("#button-two").draggable({ stack: 'div', containment: "body" }); }); $('#button-two').on('mouseup', function() { if (!$(this).hasClass('ui-draggable-dragging')) { // your click function $("#content-two").toggle(); } }); $(function() { $("#content-two").draggable({ stack: 'div', containment: "body" }); });
body, html { position: absolute; padding: 0; margin: 0; width: 100%; overflow-x: hidden; overflow-y: inherit; cursor: default; } #content { max-width: 100vw; height: 150vh; } #one { left: 5%; top: 5%; position: absolute; } #button-one { width: 100px; height: 100px; background-color: cyan; position: absolute; } #content-one { display: none; cursor: all-scroll; top: 10%; left: 10%; position: absolute; top: 20px; left: 20px; } .trip { width: 200px; height: 200px; background-color: blue; color: white; } #two { left: 15%; top: 15%; position: absolute; } #button-two { width: 100px; height: 100px; background-color: darkgrey; position: absolute; } #content-two { display: none; cursor: all-scroll; position: absolute; top: 20px; left: 20px; width: 200px; height: 200px; background-color: green; color: white; }
<div id="content"> <div id="one"> <div id="button-one">Button 1</div> <div id="content-one"> <div class="trip">div 1</div> <div class="trip">div 2</div> <div class="trip">div 3</div> </div> </div> <div id="two"> <div id="button-two">Button 2</div> <div id="content-two">Hey</div> </div> </div> <script src="https://code.jquery.com/jquery-1.7.2.min.js"></script> <script src="https://code.jquery.com/ui/1.8.21/jquery-ui.min.js"></script> <script src="https://raw.githubusercontent.com/furf/jquery-ui-touch-punch/master/jquery.ui.touch-punch.min.js"></script>
Thank you for your help! :)
Based on this answer of mine to your previous question - with some modifications I'd do it like:
data-*
attribute to store the target content selector ID Event.clientX
/ Y - to get the click coordinates .css({left: X, top: Y})
to place your content z-indexing
and help stack: '.draggable',
do its job jQuery($ => { const $drag = $('.draggable').draggable({ stack: '.draggable', containment: 'body' }); // Fix out-of-containment glitch $($drag.draggable('option').containment).on('mouseleave', () => $drag.trigger('mouseup')); let z = 10; // Contents zIndex (will increment on content toggle) $('.button').on('click', function(ev) { if ($(this).hasClass('ui-draggable-dragging')) return; $($(this).data('content')).css({left: ev.clientX, top: ev.clientY, zIndex: ++z}).toggle(); }); $('.content').on('click', function() { const $trip = $(this).find('.trip'), tripL = $trip.length; this._count |= 0; $trip.eq(++this._count % tripL).show().siblings($trip).hide(); }); });
html, body { height: 100%; margin: 0; } body { background-color: grey; } .button { width: 30vh; height: 30vh; background-color: cyan; } .content { width: 45vh; height: 45vh; display: none; cursor: all-scroll; position: absolute; background-color: blue; color: white; } .trip~.trip { display: none; } [data-content="#content-two"] {background: aquamarine;} #content-two {background: fuchsia;}
<div class="button draggable" data-content="#content-one">Toggle one</div> <div class="content draggable" id="content-one"> <div class="trip">ONE 1</div> <div class="trip">ONE 2</div> <div class="trip">ONE 3</div> </div> <div class="button draggable" data-content="#content-two">Toggle two</div> <div class="content draggable" id="content-two"> <div class="trip">TWO 1</div> <div class="trip">TWO 2</div> </div> <script src="https://code.jquery.com/jquery-1.7.2.min.js"></script> <script src="https://code.jquery.com/ui/1.8.21/jquery-ui.min.js"></script> <script src="https://raw.githubusercontent.com/furf/jquery-ui-touch-punch/master/jquery.ui.touch-punch.min.js"></script>
To achieve the order behaviour you're after, I would suggest some changes to your HTML structure. What you want to aim for is a "flat" HTML structure so that draggable elements (ie those that are currently nested in #one
and #two
) can be z-ordered relative to one another (ie in the same containing element/DIV).
With that done, you could then use the start
event hook on draggable()
to set element that's "currently on top". A simple way to do that would be to introduce a CSS class that sets the z-index
property.
To position the draggable near the button being clicked, you can use JQuerys position()
method to get the top/left coordinates of the button being clicked. You can then pass those directly to the css()
method of the draggable element like this:
/* Position of this button */
const position = $(buttonElement).position();
/* Position target near the button with slight offset */
draggableElement.css({
left : position.left + 10,
top : position.top + 10
});
The following revisions to your code should do the trick:
/* Helper function assigns the element as "top most" element relative to other elements */ function setToTop(element) { var zIndexMax = 0; $('.content, .button').each(function(i, elem) { var zIndex = Number.parseInt($(elem).css('z-index')); zIndex = Number.isNaN(zIndex) ? 0 : zIndex; zIndexMax = Math.max(zIndexMax, zIndex); }); element.css({ zIndex: zIndexMax + 1 }); } $(function() { /* Prevent drag from continuing after mouse leaves document */ $(document).mouseleave(function() { $(document).trigger("mouseup") }); $(".content, .button").draggable({ helper: "original", containment: "body", start: function(event, ui) { /* ui.helper is the element that we're starting to drag */ setToTop(ui.helper); } }); $('.trip').not(':first').hide(); }); $('.button').on('mouseup', function() { /* Cause clicked button to come to front */ setToTop($(this)); if (!$(this).hasClass('ui-draggable-dragging')) { var toggleTarget = $(".content" + $(this).data("target")); toggleTarget.toggle(); if (toggleTarget.is(':visible')) { /* Cause newly toggled element to be visible on top */ setToTop(toggleTarget); /* Position of this button */ const position = $(this).position(); /* Position target near the button with slight offset */ toggleTarget.css({ left: position.left + 10, top: position.top + 10 }); } } }); $('.content').on('mouseup', function() { if (!$(this).hasClass('ui-draggable-dragging')) { let trip = $('.trip:visible', this); let next = trip.next().length === 0 ? $('.trip:first', this) : trip.next(); trip.hide(); next.show(); } });
body, html { position: absolute; padding: 0; margin: 0; width: 100%; overflow-x: hidden; overflow-y: inherit; cursor: default; } #content { max-width: 100vw; height: 150vh; } .content { display: none; cursor: all-scroll; position: absolute; top: 20px; left: 20px; width: 200px; height: 200px; background-color: green; color: white; } .content.one { top: 10%; left: 10%; } .content.two { background-color: green; color: white; } .trip { width: 200px; height: 200px; background-color: blue; color: white; } .button { width: 100px; height: 100px; position: absolute; } #two { left: 15%; top: 15%; background-color: darkgrey; } #one { left: 5%; top: 5%; background-color: cyan; }
<div id="content"> <div id="one" class="button" data-target=".one">Button 1</div> <div id="two" class="button" data-target=".two">Button 2</div> <div class="content two">Hey</div> <div class="content one"> <div class="trip">div 1</div> <div class="trip">div 2</div> <div class="trip">div 3</div> </div> </div> <script src="https://code.jquery.com/jquery-1.7.2.min.js"></script> <script src="https://code.jquery.com/ui/1.8.21/jquery-ui.min.js"></script> <script src="https://raw.githubusercontent.com/furf/jquery-ui-touch-punch/master/jquery.ui.touch-punch.min.js"></script>
To prevent glitchcy drag behaviour continuing after the mouse leaves the document during a drag you can do this:
/*
Helper function assigns the element as "top most" element
relative to other elements
*/
function setToTop(element) {
var zIndexMax = 0;
$('.content, .button').each(function(i, elem) {
var zIndex = Number.parseInt($(elem).css('z-index'));
zIndex = Number.isNaN(zIndex) ? 0 : zIndex;
zIndexMax = Math.max(zIndexMax, zIndex);
});
element.css({
zIndex: zIndexMax + 1
});
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.