Many slider plugins that I have found are either only click to view next image or, if they do have mouse drag or touch drag capabilities, only allow images. Does anyone know of a plugin or possible way to code a mouse drag slider for any html elements? I'm specifically using an SVG, but it would be nice to have something in the future for sliding between div elements.
HTML:
<div id="slider">
<ul>
<li style="background-color: #F00"></li>
<li style="background-color: #0F0"></li>
<li style="background-color: #00F"></li>
</ul>
</div>
CSS:
#slider {
width: 400px;
overflow: hidden;
}
ul {
list-style: none;
margin: 0;
padding: 0;
}
li {
width: 400px;
height: 400px;
float: left;
}
JS:
$(function() {
var slides = $('#slider ul').children().length;
var slideWidth = $('#slider').width();
var min = 0;
var max = -((slides - 1) * slideWidth);
$("#slider ul").width(slides*slideWidth).draggable({
axis: 'x',
drag: function (event, ui) {
if (ui.position.left > min) ui.position.left = min;
if (ui.position.left < max) ui.position.left = max;
}
});
});
jsFiddle code
Related
In my web app, there is a draggable element.
I need to set the left position of this element when the element reaches a certain limit while dragging.
Using jQuery draggable widget, I have access to the position of the element:
function drag(e, ui) {
console.log(ui.position.left);
}
Let say my left attribute is setted to 1100px, I need to set it to 500px and this, without stopping the dragging.
I have three functions: dragStart, drag, and gradEnd.
Currently, I managed to get only one result: when setting ui.position.left = 500; on the drag function (using a condition), the left position is set to 500 but of course, the element is then stuck at 500px. The reason is that every time the drag function is triggered, the left position is setted to 500.
If the code runs only once the line ui.position.left = 500; the position left attribute is set to 500, but directly reset to 1100.
How can I set the left attribute once and for all?
$("#divId").draggable({
drag: drag,
})
function drag(e, ui) {
if (ui.position.top > 50) {
ui.position.left = 100;
}
}
#divId {
height: 70px;
background-color: white;
border: 4px solid #000000;
text-align: center;
color: black;
cursor: grab;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div id="divId">
Bubble
</div>
I am not sure how jQuery Draggable handles things under the hood, but even after setting ui.position.left = 100, it does not register in the event until after dragging has stopped - that is why I opted to check the actual CSS property of the element that is being targeted.
I have also provided an example (closure/functional based) which demonstrates how to handle this without having to check CSS..
First example:
$("#divId").draggable({
drag: drag
});
function drag(e, ui) {
if (ui.position.top > 50) {
$("#container").css('padding-left', '100px');
$(this).css('left', '0px');
}
if (ui.position.left < 0) {
ui.position.left = 0
}
}
#divId {
height: 70px;
background-color: white;
border: 4px solid #000000;
text-align: center;
color: black;
width: 300px;
cursor: grab;
}
#container {
height: 100vh;
width: 1000px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div id="container">
<div id="divId">
Bubble
</div>
</div>
Second example, more of a 'closure based functional approach': does not require you to check CSS..
$("#divId").draggable({
drag: drag()
});
function drag(e, ui) {
let TRIGGER = false, TOP_THRESHOLD = 50, LEFT_POSITION = 100;
return function(e, ui) {
if (TRIGGER) {
ui.position.left = LEFT_POSITION;
} else if (ui.position.top > TOP_THRESHOLD) {
TRIGGER = true;
ui.position.left = LEFT_POSITION;
}
}
}
#divId {
height: 70px;
background-color: white;
border: 4px solid #000000;
text-align: center;
color: black;
cursor: grab;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div id="divId">
Bubble
</div>
I would like to add scroll on the <ul> element if the number if <li>s is more than a particular number.
Let's say we have 12 children. I would like to show 7 of them and scroll the remain.
This is what I try:
$(document).ready(function(){
$("ul.ul-scrollable, ol.ul-scrollable").each(function (key, val) {
max_num = $(this).attr('data-maxVisible') || 8;
//console.log(max_num);
var lis = $(this).children('li');
if(lis.length > max_num) {
maxHeight = 0;
for(i = 0; i < max_num; i++) {
maxHeight += +$(lis[i]).outerHeight(true);
//console.log(maxHeight);
}
$(this).css({'max-height' : maxHeight + 'px', 'overflow-y' : 'auto'});
}
});
});
ul {
background: white;
width: 70px;
}
ul li {
padding: 3px;
margin: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<ul class="ul-scrollable" data-maxVisible="7">
<li>li1</li>
<li>li2</li>
<li>li3</li>
<li>li4</li>
<li>li5</li>
<li>li6 li6 li6</li>
<li>li7</li>
<li>li8</li>
<li>li9</li>
<li>li10</li>
<li>li11</li>
<li>li12</li>
<li>li13</li>
</ul>
But, the calculation for Height is not applicable correctly.
JS FIDDLE
An easier way of accomplishing the same effect is to grab the 7th index's distance from the top and then setting the max-height to that.
$(document).ready(function(){
$("ul.ul-scrollable, ol.ul-scrollable").each(function (key, val) {
var distance = $(this).children('li').eq(7).offset().top;
$(this).css({'max-height' : distance + 'px', 'overflow-y' : 'auto'});
});
});
ul {
background: white;
width: 70px;
}
ul li {
padding: 3px;
margin: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<ul class="ul-scrollable" data-maxVisible="7">
<li>li1</li>
<li>li2</li>
<li>li3</li>
<li>li4</li>
<li>li5</li>
<li>li6 li6 li6</li>
<li>li7</li>
<li>li8</li>
<li>li9</li>
<li>li10</li>
<li>li11</li>
<li>li12</li>
<li>li13</li>
</ul>
I'm currently in the middle making my carousel responsive. So far I've managed to make it responsive only if the user resizes and refreshes browser only then it will resize programmatically. How can I make it resize without having to refresh the browser.
Update:
I tried working with the answers below. Currently it stays on a fixed value even if I resize browser. Inside my css there is no fixed value placed
$(document).ready(function() {
var sliderWidth = 0;
var sliderContainer = $('.slider-container');
var slider = $('.slider-container .slider');
var sliderItems = $('.slider li');
var sliderContainerWidth = sliderContainer.width();
sliderItems.width(sliderContainerWidth / 2);
$('.slider-container ul.slider').children().each(function() {
sliderWidth += $(this).outerWidth();
slider.width(sliderWidth + 1000);
});
$('.btns .prev').on('click', function() {
prevSlide();
})
function prevSlide() {
var sliderItemsWidth = sliderItems.width();
var leftIndent = parseInt($(sliderItems).css('left')) - sliderItemsWidth;
function animate() {
$('.slider-container .slider:not(:animated)').animate({
'left': leftIndent
}, 100)
}
animate();
}
})
.wrapper {
max-width: 1280px;
margin: 0 auto;
background-color: #ccc;
}
.wrapper .slider-container {
float: left;
position: relative;
overflow: hidden;
width: 100%;
background-color: beige;
}
.wrapper .slider-container .slider {
display: flex;
flex-wrap: wrap;
position: relative;
}
.wrapper .slider-container .slider li {
height: 300px;
background-color: #ccc;
position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="wrapper">
<div class="slider-container">
<ul class="slider">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<ul class="btns">
<li class="prev">prev</li>
<li class="next">next</li>
</ul>
</div>
</div>
As per my comments, you can put the resizing bits into a function and call that on window resize:
$(document).ready(function() {
var sliderContainer = $('.slider-container');
var slider = $('.slider-container .slider');
var sliderItems = $('.slider li');
function resize() {
var sliderWidth = 0;
var sliderContainerWidth = sliderContainer.width();
sliderItems.width(sliderContainerWidth / 2);
$('.slider-container ul.slider').children().each(function() {
sliderWidth += $(this).outerWidth();
slider.width(sliderWidth + 1000);
});
}
$('.btns .prev').on('click', function() {
prevSlide();
})
function prevSlide() {
var sliderItemsWidth = sliderItems.width();
var leftIndent = parseInt($(sliderItems).css('left')) - sliderItemsWidth;
function animate() {
$('.slider-container .slider:not(:animated)').animate({
'left': leftIndent
}, 100)
}
animate();
}
resize(); // call onload
$(window).on('resize', function () {
resize(); // call when browser is resized
});
})
I'm trying to achieve a responsive menu similar to Google Plus, where the main menu options are added to or removed from the "more" drop down as the window is resized.
The menu I have currently looks like this:
Here is the code:
// JQuery
$(document).ready(function() {
$("a.drop-menu").click(function () {
$('#drop-menu').toggle();
});
});
<!-- HTML -->
<ul id="navigation">
<li>Home</li>
<li>About</li>
<li>Calendar</li>
<li>Forum</li>
<li>Gallery</li>
<li>More
<ul id="drop-menu">
<li>Contact</li>
<li>Contact</li>
</ul></li>
</ul>
/* CSS */
#navigation {
list-style-type: none;
padding: 0px;
margin: 0px;
}
#navigation li {
display: inline-block;
}
#navigation li a:link, #navigation li a:visited, #navigation li a:active {
display: block;
width: 120px;
line-height: 50px;
text-align: center;
font-weight: bold;
text-decoration: none;
background-color: #27383F;
color: #CCC8C0;
}
#navigation li a:hover, #navigation li a.active {
background-color: #2C3C53;
}
#drop-menu {
display: none;
position: absolute;
padding: 0px;
margin: 0px;
}
#drop-menu li {
display: block;
}
JSFiddle
Currently, when the browser window is re-sized the menu options collapse as follows:
However, the below image is my desired result:
I'm wondering if there is a way to accomplish this without media queries? More specifically:
How can I dynamically detect whether the window size is large enough or too small to contain the li tags in the main navigation on a single line?
How do I swap the li tags between one menu and the other?
By not using media-queries I think you can use jQuery $( window ).width(); which will return width of browser viewport.. It should be like this:
$(document).ready(function() {
$("a.drop-menu").click(function () {
$('#drop-menu').toggle();
});
if($( window ).width() < $("#navigation > li").length * (120 + 5)){
//5px is the approximation of the gap between each <li>
var html = $("#navigation > li").last().prev().html();
$("#navigation > li").last().prev().remove();
$("#drop-menu").append(html);
}
var bigger = $("#navigation > li").length + 1;
var smaller = $("#navigation > li").length;
$( window ).resize(function() {
if($( window ).width() <= smaller * (120 + 5)){
//5px is the approximation of the gap between each <li>
var html = $("#navigation > li").last().prev().html();
if(html != undefined){
$("#navigation > li").last().prev().remove();
$("#drop-menu").prepend("<li>"+html+"</li>");
bigger = $("#navigation > li").length + 1;
smaller = $("#navigation > li").length;
}
}
if($( window ).width() >= bigger * (120 + 5)){
//5px is the approximation of the gap between each <li>
var html = $("#drop-menu > li").first().html();
if(html != undefined){
$("#drop-menu > li").first().remove();
$("#navigation > li").last().before("<li>"+html+"</li>");
bigger = $("#navigation > li").length + 1;
smaller = $("#navigation > li").length;
}
};
});
});
Check out this Fiddle, I believe it's not the perfect result.. But, I believe you can use it as your starting point.. Hope it helps..
How can I make the carousel center the item I've clicked to the middle? I've looked everywhere for an answer but they're not straight answers... Can someone help me in this, please?
This is what I've done so far: http://jsfiddle.net/sp9Jv/
HTML:
<div id="wrapper">
<div id="carousel">
prev
next
<div class="viewport">
<ul>
<li>Un</li>
<li>Deux</li>
<li>Trois</li>
<li>Quatre</li>
<li>Cinq</li>
<li>Six</li>
<li>Sept</li>
<li>Huit</li>
</ul>
</div>
<!-- viewport -->
</div>
<!-- carousel -->
</div>
<!-- wrapper -->
JavaScript:
var carousel = $('#carousel'),
prev = carousel.find('.prev'),
next = carousel.find('.next'),
viewport = carousel.find('.viewport'),
item = viewport.find('li'),
itemWidth = item.outerWidth(true),
itemNum = item.length,
itemList = viewport.find('ul');
itemList.width(itemWidth * itemNum);
var moveCarousel = function(dir) {
itemList.animate({ left: '-=' + (itemWidth * dir) + 'px' }, 400);
};
//prev
prev.on('click', function(e) {
e.preventDefault();
moveCarousel(-1);
});
//next
next.on('click', function(e) {
e.preventDefault();
moveCarousel(1);
});
//carousel item
item.on('click', 'a', function(e) {
var self = $(this),
selfIndex = self.index(),
distance = itemList.width() / 2,
selfPos = self.position(),
selfPosLeft = selfPos.left,
viewportPosLeft = viewport.position().left;
e.preventDefault();
//move item to middle, but it doesn't work...
if (selfPosLeft > Math.floor(viewport.width())/3) {
itemList.animate({ left: '-' + Math.floor(viewport.width())/3 + 'px' }, 400);
}
if (selfPosLeft < Math.floor(viewport.width())/3) {
itemList.animate({ left: Math.floor(viewport.width())/3 + 'px' }, 400);
}
});
CSS:
#wrapper {
width: 500px;
margin: 20px auto;
}
#carousel {
position: relative;
}
.viewport {
width: 260px;
border: 1px solid #6e6e6e;
height: 80px;
overflow: hidden;
position: relative;
margin-left: 100px;
}
.prev, .next {
position: absolute;
}
.prev {
top: 20px;
left: 0;
}
.next {
top: 20px;
right: 0;
}
.viewport ul {
position: absolute;
}
.viewport li {
float: left;
margin-right: 10px;
}
.viewport li a {
display: block;
width: 80px;
height: 80px;
background: #ddd;
}
While you have prepared all the information needed about all items, you can calculate the value of the left based on the clicked item.
Here is my modification:
and I've bound the click action of carousel items with this function and passed the clicked item using the self keyword.
var itemClicked=function(item){
var itemIndex=$(item).index(),
newLeft=(itemIndex*itemWidth*-1)+Math.floor(($(viewport).width()/itemWidth)/2)*itemWidth;
$(itemList).animate({left:newLeft+"px"},400);
};
You can check it working on this url: http://jsfiddle.net/rUZHg/3/
I assume that this should work despite of the number of viewed elements while it calculates the padding between the left 0 and the left of the center element.
Alright, it's ugly, I hope it gives you some ideas.
I created a global currentItem that tracks what's in the center. Every time the carousel moves this is updated.
The very useful variable I found was selfPosLeft which told me what was being clicked. I should add that 90 was the multiple I got from clicking around. Must be linked to your CSS and I don't know how to find this number dynamically.
Please try it :) http://jsfiddle.net/sp9Jv/4/
Well, I'm picturing that when you have more than 3 items you can change the code to compute the difference between the current item and the selfPosLeft of the clicked one, I'll leave that to you :) Like this, seems to work. http://jsfiddle.net/sp9Jv/5/