I am trying to toggle the image src on click instead of mouseout & in.
I have multiple images,I want to toggle the image of single product, if buttons which exist in same parent div of image, will click.
Any thoughts ?
function toggleImage(thisimage) {
thisimage.toggle();
}
.prev_btn {
position: absolute;
left: 7px;
top: 30px;
bottom: 0;
width: 30px;
height: 128%;
z-index: 2;
border-style: dotted;
}
.next_btn {
position: absolute;
right: 65%;
top: 30px;
bottom: 0;
width: 30px;
height: 128%;
z-index: 2;
border-style: dotted;
}
<div id="pro"><img width="206" height="260" src="https://www.w3schools.com/html/pic_trulli.jpg" onmouseover="this.src='https://www.w3schools.com/html/img_chania.jpg'" onmouseout="this.src='https://www.w3schools.com/html/pic_trulli.jpg'">
<div class="prev_btn" onclick="toggle(this)"></div>
<div class="next_btn" onclick="toggle(this)"></div>
</div>
Using jQuery you would do it like this.
Please give a class to your image element. Otherwise you can also toggle all image tags.
$('.prev_btn, .next_btn').on('click', function(e) {
$('.img').toggle();
});
If you want to toggle all images, then just:
$('img').toggle();
First, move your images into an array on a data- attribute on the image itself - this gives you different set of images and any number of images - rather than just toggle between two, which you don't need next and previous buttons, so the implication is that you want more than two images.
<img data-images='["https://www.w3schools.com/html/img_chania.jpg","https://www.w3schools.com/html/pic_trulli.jpg"]' ...
Next, use js/jquery event handlers rather than HTML onclick= just gives you more control and separation of html/code etc (see other SO questions for more info)
$(".prev_btn").click(function() {
Within this handler, we find the relevant image using your parent wrapper. Here I've given the wrapper a class rather than an id so that you can have multiple wrappers without needing different IDs and easier to style in css (rather than .closest("div"))
$(this).closest(".wrapper").find("img").first()
and the click event handler calls a common method with the direction (rather than repeat all the same code)
This stores on each image the current index so no need for additional variables to "remember"
img.data("index", new_index);
Then it's a case of reading the array from the image, changing the index based on direction and updating the image.
I've had to make some tweaks to your CSS for the buttons (just for demo) and the 2nd image includes a 3rd image url to show it working with more than just toggle
$(".prev_btn").click(function() {
changeImage($(this).closest(".wrapper").find("img").first(), -1)
});
$(".next_btn").click(function() {
changeImage($(this).closest(".wrapper").find("img").first(), 1)
});
function changeImage(img, direction)
{
var images = img.data("images");
var idx = img.data("index");
idx += direction;
if (idx >= images.length) idx = 0;
if (idx < 0) idx = images.length - 1;
img
.data("index", idx)
.attr("src", images[idx]);
}
.wrapper {
position:relative;
}
.prev_btn, .next_btn {
position:absolute;
left: 0;
top: 0px;
bottom: 0;
width: 30px;
height: 255px;
z-index: 2;
border-style: dotted;
}
.next_btn {
left: 170px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="wrapper">
<img width="206" height="260"
src="https://www.w3schools.com/html/pic_trulli.jpg"
data-images='["https://www.w3schools.com/html/img_chania.jpg","https://www.w3schools.com/html/pic_trulli.jpg"]'
data-index="1">
<div class="prev_btn"></div>
<div class="next_btn"></div>
</div>
<div class="wrapper">
<img width="206" height="260"
src="https://www.w3schools.com/html/img_chania.jpg"
data-images='["https://www.w3schools.com/html/img_chania.jpg","https://www.w3schools.com/html/pic_trulli.jpg", "https://www.w3schools.com/html/img_girl.jpg"]'
data-index="0">
<div class="prev_btn"></div>
<div class="next_btn"></div>
</div>
$('.prev_btn, .next_btn').on('click', function(e) {
var this$ = $(e.currentTarget), // grab the currently clicked button element
parent$ = this$.parents('#pro').first(), // grab the parent of the button that has the id #pro
contextBasedImgs$ = parent$.find('img'); // grab all the images in the parent div with id #pro
contextBasedImgs$.each(function(ignore, el) {
var currEl$ = $(el),
newURI = currEl$.attr('onmouseout');
currEl$.attr('src', newURI);
});
});
Related
I'm trying to create a slideshow for a project.
The code I've built is fairly simple but for some reason I can only make the next arrows work, not the previous.
When you click next it removes the class active from the current image, adds that class to the next image and changes the display to the new active image.
When you click previous it removes the active class but doesn't add any classes to any other elements. It then changes the display to the final image for some reason.
I've tried rearranging the order that the functions are called in. I've also tried to see what happens when the active class is added to the last image (it has the same problem but in reverse, so now next doesn't work but previous is fine).
var activeSlide = $('.active');
var nextSlide = activeSlide.next('.slide');
var prevSlide = activeSlide.prev('.slide');
var arrow = $('.arrow');
var firstSlide = $('.first');
var lastSlide = $('.last');
// slideshow functions
// next arrow
function nextArrow () {
if (!activeSlide.hasClass('last')) {
activeSlide.removeClass('active');
nextSlide.addClass('active');
activeSlide = nextSlide;
nextSlide = activeSlide.next('.slide');
// check if new slide is last slide and remove the click button
if (activeSlide.hasClass('last')) {
$('.next').fadeOut();
}
}
};
// previous arrow
function prevArrow () {
if(!activeSlide.hasClass('first')) {
activeSlide.removeClass('active');
prevSlide.addClass('active');
activeSlide = prevSlide;
prevSlide = activeSlide.prev('.slide');
// check if new slide is the first slide and remove the click button
if (activeSlide.hasClass('first')) {
$('.previous').fadeOut();
}
}
};
//click element and call functions
$('.arrow').click( function () {
if ($(this).hasClass('next')) {
nextArrow();
} else {
prevArrow();
}
});
#slideshow {
position: relative;
height: 400px;
width: 600px;
margin: 15% auto;
}
.slide {
position: absolute;
top: 0;
left: 0;
z-index: 8;
height: 100%;
width: 100%;
}
.active {
z-index: 10;
}
.arrow {
text-decoration: none;
display: inline-block;
padding: 8px 16px;
}
.arrow:hover {
background-color: #ddd;
color: black;
opacity: 0.9;
cursor: pointer;
}
.previous {
left: 0;
}
.next {
right: 0;
}
.arrow {
z-index: 11;
background-color: #ddd;
color: black;
position: absolute;
top: 50%;
opacity: 0.5;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="slideshow">
<div id="slides">
<img class="slide active first" src="Toscana 1.jpg" alt="image of toscana, slideshow image 1" />
<img class="slide" src="Toscana 2.jpg" alt="image of toscana, slideshow image 1" />
<img class="slide" src="Toscana 3.jpg" alt="image of toscana, slideshow image 2" />
<img class="slide last" src="Toscana 4.jpg" alt="image of toscana, slideshow image 3" />
</div>
<div class="previous arrow">‹</div>
<div class="next arrow">›</div>
</div>
<script src="javascript/practice.js"></script>
In theory you should be able to click next and see the next image in the sequence. Then when you want to see the previous image in the sequence you should be able to click previous whereby it will remove the active class from the current image and add it to the image before.
Really appreciate the help understanding what's going wrong if anyone is able to help at all.
You're depending on global variables to maintain your program state, but aren't always managing to keep the state of the variables matching up with the state of the DOM.
It's probably better to use the DOM as a single source of truth: the "active" slide is whichever node currently has the "active" class, and you can calculate the next and previous ones based on its position.
This also needed some work on the "next" / "previous" button visibility: you were hiding buttons at the end and beginning of the range, but never brought them back; you also need to load with the "previous" button disabled initially.
//No global variables. Use $('.active') to determine the currently active slide
// next arrow
function nextArrow() {
var activeSlide = $('.active');
if (activeSlide.hasClass('last')) return; // bail if the user managed to click the 'next' button while it was fading out
activeSlide.removeClass('active');
activeSlide.next().addClass('active');
// $('.active') is now the "next" slide
if ($('.active').hasClass('last')) {
$('.next').fadeOut();
}
// Always bring back the "previous" button when user hits next:
$('.previous').fadeIn();
};
// previous arrow
function prevArrow() {
var activeSlide = $('.active');
if (activeSlide.hasClass('first')) return;
activeSlide.removeClass('active');
activeSlide.prev().addClass('active');
if ($('.active').hasClass('first')) {
$('.previous').fadeOut();
}
$('.next').fadeIn();
};
//click element and call functions
// removing the unnecessary intermediate function here:
$('.next').click(nextArrow)
$('.previous').click(prevArrow)
#slideshow {
position: relative;
height: 200px;
width: 300px;
margin: 15% auto;
}
.slide {
position: absolute;
top: 0;
left: 0;
z-index: 8;
height: 100%;
width: 100%;
}
.active {
z-index: 10;
}
.arrow {
text-decoration: none;
display: inline-block;
padding: 8px 16px;
}
.arrow:hover {
background-color: #ddd;
color: black;
opacity: 0.9;
cursor: pointer;
}
.previous {
left: 0;
display:none;
}
.next {
right: 0;
}
.arrow {
z-index: 11;
background-color: #ddd;
color: black;
position: absolute;
top: 50%;
opacity: 0.5;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="slideshow">
<div id="slides">
<img class="slide active first" src="https://placehold.it/600x400" alt="image of toscana, slideshow image 1" />
<img class="slide" src="https://placehold.it/601x401" alt="image of toscana, slideshow image 2" />
<img class="slide" src="https://placehold.it/602x402" alt="image of toscana, slideshow image 1" />
<img class="slide last" src="https://placehold.it/603x403" alt="image of toscana, slideshow image 1" />
</div>
<div class="previous arrow">‹</div>
<div class="next arrow">›</div>
</div>
You're not setting a prevSlide in your next arrow function. so when you start, prevSlide is null. then you click the next arrow button and you set the active slide to the nextSlide, then set the nextSlide to one after the active, but you're not setting the previous slide so it stays null
eg slide 1 = current-slide, slide 2 = about-to-be-active, slide 3 = about-to-be-next
operation of clicking the next arrow should be:
set prevSlide to current-slide (this action doesn't happen)
set activeSlide to next-slide
set nextSlide to next-slide.next
similarly in your prevArrow, you need to set the nextSlide
you can try the class $ ('. active');
if(!activeSlide.hasClass('first')) {
var currentSlide = $('.active');
var prevSlide = currentSlide.prev();
currentSlide.removeClass('active');
prevSlide.addClass('active');
I'm calling images from a folder at random and putting them in HTML img tags using PHPs glob function.
I'm then using JS to read the URLs and flip the CSS background image of div#wrapper, 300ms for each image. The images should be preloaded as they have HTML img tags. They are being hidden from the user using the following CSS (which should not stop preloading as "display: none" does):
.visuallyhidden {
position: absolute;
overflow: hidden;
clip: rect(0 0 0 0);
height: 1px; width: 1px;
margin: -1px; padding: 0; border: 0;
}
Nonetheless I'm experiencing the images flashing inconsistently / at different rates. It seems that larger file size images cause this to happen, but the images should be preloaded so I'm not sure why this is occurring.
My JS looks like this:
var slides = [];
$('.slide').each(function(index){
slides.push($(this).attr('id'));
});
var slide = 0;
function changeImage(){
if (slide < 10){
var currentSlide = $("#" + slides[slide]);
$('#wrapper').css('background-image', '');
$('#wrapper').css('background-image', 'url("' + currentSlide.attr('src') + '")');
slide++
} else {
$('#headline').removeClass('visuallyhidden');
$('#wrapper').css('background-image', '');
$('#wrapper').css('background-color', '#ef3308');
}
}
setInterval(changeImage, 300);
The site is http://robertirish.com.
Is there a better way to do this / can anyone explain why it's happening?
I'm going to guess it's a loading issue: either that CSS is interfering with preload or else it's being treated differently because you're loading it into the background of another element rather than using the img that you preloaded. Instead, I would load all the images inside the div, absolute-positioned on top of each other, and then just remove them one by one:
CSS:
#wrapper{
position: relative;
}
#wrapper img{
position: absolute;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
}
HTML:
<div id="wrapper">
<img src="image1.png">
<img src="image2.png">
<!--etc-->
</div>
JS:
$(document).on('ready', function(){
var images = [];
$("img", "#wrapper").each(function(){
images.push(this);
});
var timer = setInterval(function(){
if (images.length)
$(images.pop()).remove();
else
clearInterval(timer);
}, 300);
});
So I have a map composed by tiles that are svg elements.
In the image, the tile itself is the blue area, but it has a buffer area to allow geometries that span outside the tile to render whole. The problem is that this buffer area (in green), is covering the geometries from other tiles that are below it. This buffer zone is set in CSS as the following:
padding: 128px;
margin: -128px;
Is there a way to hover/click "through" the buffer area, or is there a better approach in CSS to achieve this?
Padding is part of a element, therefore will react like it was content of your tag.
See here. If you absolutely need to have that spacing to be padding, you can't click anything behind neither content nor padding.
You might consider changing your layering, using z-index, but for further advise on this, you'll have to provide further code, your HTML Markup and CSS code.
If that blue thingy is the only element that needs this treatment, then I suggest creating a key bind to move that element to the back with z-index, and be done with it.
If you require this functionality on all of these red balls, the thing to do would probably be to move, the one you click on, to the back with z-index ( again ).
Both of these require you to use JavaScript most likely, unless you want to move that big blue element to the back on hover.
To always move the clicked element to the back you could just keep track of what was the last assigned z-index, and decrease it by one every time you assign it to a new object.
Something like this would probably do:
#box1 { position: absolute; background-color: #123; width: 100px; height: 100px; top: 200px; left: 300px; opacity: 0.9; }
#box2 { position: absolute; background-color: #ABC; width: 100px; height: 100px; top: 250px; left: 350px; opacity: 0.8; }
<div class="box" id="box1"></div>
<div class="box" id="box2"></div>
<script type="text/javascript">
var boxes = document.getElementsByClassName("box");
var length = boxes.length;
var index = 0;
function moveToBack(event)
{
var element = this;
this.style.zIndex = index;
index--;
return false;
}
for(var i = 0; i < length; i++)
{
var box = boxes[i];
box.addEventListener("click", moveToBack, false);
}
</scirpt>
Does that do the job ? or did you mean something else entirely ?
Only way I can seem to get it to work is to add a child inner element and give pointer-events:none to the wrapper and pointer-events:auto to the inner child element. It's not ideal as support for pointer-events is limited and there's no telling if all browsers will respect a child of pointer-events:none element having a different value than its parent. It will need tested. Well, in any case, here is the code:
$('.tile').on('mouseenter', function(){
$('.info', this).find('.tile-info').remove();
var ts = new Date().getTime();
$('.info', this).append('<div class="tile-info">mouseenter tile '+ts+'</div>');
});
$('.tile').on('mouseleave', function(){
$('.info', this).find('.tile-info').remove();
var ts = new Date().getTime();
$('.info', this).append('<div class="tile-info">mouseleave tile '+ts+'</div>');
});
$('.inner').on('mouseenter', function(){
$('.info', this).find('.inner-info').remove();
var ts = new Date().getTime();
$('.info', this).append('<div class="inner-info">mouseenter inner '+ts+'</div>');
});
$('.inner').on('mouseleave', function(){
$('.info', this).find('.inner-info').remove();
var ts = new Date().getTime();
$('.info', this).append('<div class="inner-info">mouseleave inner '+ts+'</div>');
});
.tile {
width: 200px;
height: 200px;
background: rgba(100,100,200,0.2);
padding: 50px;
margin: -50px;
position: absolute;
pointer-events:none;
}
.tile:nth-of-type(1) {left: 300px;top: 20px;}
.tile:nth-of-type(2) {left: 90px;top: 210px;}
.tile:nth-of-type(3) {left: 0px;top: 0px;}
.tile:nth-of-type(4) {left: 360px;top: 240px;}
.tile .inner {
width: 100%;
height: 100%;
background: rgba(200,100,100,0.2);
pointer-events:auto;
overflow: auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="tile">
<div class="inner">
<div class="info"></div>
</div>
</div>
<div class="tile">
<div class="inner">
<div class="info"></div>
</div>
</div>
<div class="tile">
<div class="inner">
<div class="info"></div>
</div>
</div>
<div class="tile">
<div class="inner">
<div class="info"></div>
</div>
</div>
I wonder what are the best(good readable code, pest practice code,reusability) concepts to build a Infinity-Image-Loop-Slider for a Website using JavaScript/jQuery? I dont what to know how to code the Slide show but what blueprint matches the requirements mention above.
The main focus of my question is how to arrange the pictures to get the impression of a infinity loop Slider.
By look at Code from different Sliders I came across two solutions:
-change the z-Index of all Images each time the next/previous image is displayed.
-change the Position of the Image in the DOM.
But examine and understanding the code of others is very time-consuming - that's why I ask this question :-)
tl;dr - JSBin Example: http://jsbin.com/ufoceq/8/
A simple approach to create an infinite image slider without too much effort is as follows: let say for the sake of simplicity that you have <n> images to slide in a loop, so that after the nth image the next one to visualize is the 1st (and vice-versa).
The idea is to create a clone of first and last image so that
the clone of the last image is prepended before the first one;
the clone of the first image is appended after the last one.
Whatever is the amount of your images, you will need to append at most only 2 cloned elements.
Again for the simplicity, let say that all images are 100px wide and they're wrapped in a container that you move left/right into a clipped mask with overflow: hidden. Then, all images can be easily aligned in a row with display: inline-block and white-space: nowrap set on the container (with flexbox now it is even easier).
For n = 4 The DOM structure would be something like this:
offset(px) 0 100 200 300 400 500
images | 4c | 1 | 2 | 3 | 4 | 1c
/* ^^ ^^
[ Clone of the last image ] [ Clone of the 1st image ]
*/
At the beginning, your container will be positioned with left: -100px (or also margin-left: -100px or even better (for a matter of performance) transform: translateX(-100px) ), so the slider can show the first image. To switch from an image to another you will need to apply a javascript animation over the same property you've previously chosen.
When your slider is currently at the 4th image, you have to switch from image 4 to 1c, so the idea is to execute a callback at the end of the animation that soon reposition your slider wrapper at the real 1st image offset (e.g. you set left: -100px to the container)
This is analogous when your slider is currently positioned on the 1st element: to show the previous image you just need to perform an animation from image 1 to 4c and when animation has been completed you just move the container so the slider is istantly positioned at the 4th image offset (e.g. you set left: -400px to the container).
You can see the effect on the above fiddle: this is the minimal js/jquery code I used (of course the code can be even optimized so the width of the items is not hardcoded into the script)
$(function() {
var gallery = $('#gallery ul'),
items = gallery.find('li'),
len = items.length,
current = 1, /* the item we're currently looking */
first = items.filter(':first'),
last = items.filter(':last'),
triggers = $('button');
/* 1. Cloning first and last item */
first.before(last.clone(true));
last.after(first.clone(true));
/* 2. Set button handlers */
triggers.on('click', function() {
var cycle, delta;
if (gallery.is(':not(:animated)')) {
cycle = false;
delta = (this.id === "prev")? -1 : 1;
/* in the example buttons have id "prev" or "next" */
gallery.animate({ left: "+=" + (-100 * delta) }, function() {
current += delta;
/**
* we're cycling the slider when the the value of "current"
* variable (after increment/decrement) is 0 or when it exceeds
* the initial gallery length
*/
cycle = (current === 0 || current > len);
if (cycle) {
/* we switched from image 1 to 4-cloned or
from image 4 to 1-cloned */
current = (current === 0)? len : 1;
gallery.css({left: -100 * current });
}
});
}
});
});
As mentioned before, this solution doesn't require really much effort and talking about performance, comparing this approach to a normal slider without looping, it only requires to make two additional DOM insertion when the slider is initialized and some (quite trivial) extra logic to manage a backward/forward loop.
Here is another example when you see two elements at once: in that case you need to clone more elements and make some simple changes to the logic
https://codepen.io/fcalderan/pen/bGbjZdz
I don't know if a simpler or better approach exists, but hope this helps anyway.
Note: if you need to also have a responsive gallery, maybe this answer may help too
I've just created the item slider: check it out:
https://github.com/lingtalfi/jItemSlider/blob/master/README.md
It's 600 lines of code, maybe you can simply browse it.
The idea behind it is inspired by the netflix slider (as of 2016-02-24).
Basically, it uses css transform translations, because those are the fastest/slickest in a browser.
http://eng.wealthfront.com/2015/05/19/performant-css-animations/
Now the basic concept behind the slide movement, is that you only display the current visible slice,
but you also have one invisible slice on the left, and another invisible slice on the right.
And, you also have two extra items, one on each side, so that your items look like this:
previous items - prev extra item - main items - next extra item - next items
Only the main items are visible.
The extra items are partially visible.
The previous and next items are invisible.
More details here:
https://github.com/lingtalfi/jItemSlider/blob/master/doc/conception.md
Now when you slide to the right (for instance), you basically append more items to the right side,
and then remove those from the left side.
This technique is the greatest I've encountered so far, because you don't deal with a long list of items (using
cloning without removing the invisible items), which can make your animation slower.
Note: my first try of this slider was actually cloning without removing, it works, but I don't like it:
https://github.com/lingtalfi/jInfiniteSlider
Also, it's item based (rather than pixels based), and in the end, that's what the user expects because
everything is always aligned, as it should be.
Vanila Javascript!! No-clone technique, getElementsByClassName to the rescue
document.getElementsByClassName selection is a live collection; any changes in DOM is updated in the stored variable unlike querySelector method.
In this technique, we just shift the first slide to the end if we reach the last slide while clicking right or we shift the last slide at the beginning when we reach the first slide while clicking left. Clone creation is not required here. The getElementsByClassName method gives us a live HTML collection to work with which updates as we make changes in the DOM. (In this case, changes in the order of divs)
Here is my GitHub Repository
// slider
const slides = document.getElementsByClassName("slide"); // this selection is a live collection; any changes in DOM is updated in the variable unlike querySelectors
const btnLeft = document.querySelector(`.btn-left`);
const btnRight = document.querySelector(`.btn-right`);
let currentSlideIndex = 0;
let lastSlideIndex = slides.length - 1;
// go to a slide;
function goToSlide(slideIndex) {
[...slides].forEach((s, i) => {
s.style.transform = `translateX(${100 * (i - slideIndex)}%)`
})
currentSlideIndex = slideIndex;
}
goToSlide(currentSlideIndex);
// make ready the next slide if current slide is the first or the last slide
function readyNextSlide() {
// if currentSlide is the last slide, shift the first slide to the end
if (currentSlideIndex === lastSlideIndex) {
slides[lastSlideIndex].insertAdjacentElement("afterend", slides[0]);
slides[lastSlideIndex].style.transform = `translateX(${100}%)`;
currentSlideIndex--; //this is because current slide is now the second last slide
}
// if currentSlide is the first slide, shift the last slide to the beginning
if (currentSlideIndex === 0) {
slides[0].insertAdjacentElement("beforebegin", slides[lastSlideIndex]);
slides[0].style.transform = `translateX(-${100}%)`;
currentSlideIndex++; //this is because current slide is now the second slide
}
}
// put the last slide in the beginning; ('if' condition is not necessary but providing if condition is future proof if user sets the initial slide to be shown as the last slide )
if (currentSlideIndex === lastSlideIndex || currentSlideIndex === 0) readyNextSlide();
// shift all slides left or right based on direction provided
function shiftSlides(direction) {
direction ? currentSlideIndex++ : currentSlideIndex--
if (currentSlideIndex === lastSlideIndex || currentSlideIndex === 0) readyNextSlide();
goToSlide(currentSlideIndex);
}
//button click events
btnRight.addEventListener("click", shiftSlides.bind(null, 1));
btnLeft.addEventListener("click", shiftSlides.bind(null, 0));
body {
display: grid;
height: 100vh;
width: 100vw;
align-items: center;
align-content: center;
justify-content: center;
}
.slider {
position: relative;
width: 600px;
height: 300px;
transform: scale(0.8);
overflow: hidden; /* remove overflow to see what's going on*/
}
.slide {
position: absolute;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
transition: transform 1s;
}
.slide b {
position: absolute;
font-size: 10em;
color: black;
opacity: 0.6;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.s1 {
background-color: cornflowerblue;
}
.s2 {
background-color: bisque;
}
.s3 {
background-color: coral;
}
.s4 {
background-color: thistle;
}
.btn {
position: absolute;
top: 50%;
z-index: 10;
border: none;
background: crimson;
font-family: inherit;
color: white;
height: 5.5rem;
width: 5.5rem;
font-size: 3.25rem;
cursor: pointer;
}
.btn-left {
left: 6%;
transform: translate(-50%, -50%);
}
.btn-right {
right: 6%;
transform: translate(50%, -50%);
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Infinity Looping Rotating slider</title>
<link rel="stylesheet" href="slider.css">
<script src="slider.js" defer></script>
</head>
<body>
<div class="slider">
<div class="slide s1"><b>1</b></div>
<div class="slide s2"><b>2</b></div>
<div class="slide s3"><b>3</b></div>
<div class="slide s4"><b>4</b></div>
<button class="btn btn-left">←</button>
<button class="btn btn-right">→</button>
</div>
<p>
<b>
This is my response to a questing in StackOverflow about infinity loop slider.<br>
My github repo is Infinity loop Slider by Dibakash
</b>
</p>
</body>
</html>
Thanks a lot of this article!
I had update and used above code.
I hope this will help everyone.
Poor developer.
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>Directive slider</title>
<style>
/* 四联切换焦点图 */
.slides-wrapper{ position: relative; width: 100%; margin: 10px 0; }
.gallery { position: relative; width: 1200px; height: 180px; overflow:hidden; }
.gallery ul { font-size: 0; white-space: nowrap; position: absolute; top: 0; left: -1200px; margin: 0; padding: 0; }
.gallery li { display: inline-block; vertical-align: top; width: 1200px; height: 180px; white-space: normal; }
.gallery li img{ width: 298px; height:180px; padding: 1px; }
.gallery .arrow { background: url(/shop/templates/default/images/home_bg.png) no-repeat; background-size: 150px 223px; width: 35px; height: 70px; position: absolute; z-index: 2; top: 50px; cursor: pointer; opacity: 0;}
.gallery .prev { background-position: 1px -92px; left: 0;}
.gallery .next { background-position: -30px -92px; right: 0px;}
</style>
<style type="text/css">
.demo_wrapper{
margin: 0 auto;
width: 1200px;
}
.demo_wrapper .title{
text-align: center;
}
</style>
</head>
<body>
<div class="demo_wrapper">
<div class="title">
<h1>Directive slider (Published by fenmingyu)</h1>
</div>
<!-- demo content -->
<div class="slides-wrapper">
<div class="gallery" id="top_sale_gallery">
<ul>
<li>
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-1-1.jpg?234" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-1-2.jpg?752" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-1-3.jpg?320" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-1-4.jpg?365" alt="">
</li>
<li>
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-2-1.jpg?852" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-2-2.jpg?746" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-2-3.jpg?525" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-2-4.jpg?550" alt="">
</li>
</ul>
<div class='arrow prev'></div>
<div class='arrow next'></div>
</div>
<div class="gallery" id="top_goods_gallery">
<ul>
<li>
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-3-1.jpg?793" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-3-2.jpg?180" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-3-3.jpg?550" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-3-4.jpg?851" alt="">
</li>
<li>
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-1-1.jpg?234" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-1-2.jpg?752" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-1-3.jpg?320" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-1-4.jpg?365" alt="">
</li>
<li>
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-2-1.jpg?852" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-2-2.jpg?746" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-2-3.jpg?525" alt="">
<img src="http://imgserv.5thmedia.cn/upload_test/shop/editor/web-102-104-2-4.jpg?550" alt="">
</li>
</ul>
<div class='arrow prev'></div>
<div class='arrow next'></div>
</div>
<div style="clear: both;"></div>
</div>
</div>
</body>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
$(function() {
$.fn.gallery = function(settings) {
var defaults = {
time: 3000,
direction:1
};
var settings = $.extend(defaults, settings);
var gallery_wrapper = $(this),
gallery = gallery_wrapper.find('ul'),
items = gallery.find('li'),
len = items.length,
current = 1, /* the current item we're looking */
first = items.filter(':first'),
last = items.filter(':last'),
w = gallery.find('li').width(),
triggers = gallery_wrapper.find('.arrow');
var show_slide = function(direction,w){
gallery.animate({ left: "+=" + (-w * direction) }, function() {
current += direction;
/**
* we're cycling the slider when the the value of "current"
* variable (after increment/decrement) is 0 or when it exceeds
* the initial gallery length
*/
cycle = !!(current === 0 || current > len);
if (cycle) {
/* we switched from image 1 to 4-cloned or
from image 4 to 1-cloned */
current = (current === 0)? len : 1;
gallery.css({left: -w * current });
}
});
};
var picTimer = setInterval(function() {
show_slide(settings.direction,w);
},
settings.time);
return this.each(function(){
/* 1. Cloning first and last item */
first.before(last.clone(true));
last.after(first.clone(true));
/* 2. Set button handlers */
triggers.on('click', function() {
if (gallery.is(':not(:animated)')) {
var cycle = false;
settings.direction = ($(this).hasClass('prev'))? -1 : 1;
/* in the example buttons have id "prev" or "next" */
show_slide(settings.direction,w);
}
clearInterval(picTimer);
picTimer = setInterval(function() {
show_slide(settings.direction,w);
},
settings.time);
});
/* hover show arrows*/
show_slide(settings.direction,w);
gallery_wrapper.hover(function() {
$(this).find(".arrow").css("opacity", 0.0).stop(true, false).animate({
"opacity": "0.3"
},
300);
},function(){
$(this).find(".arrow").css("opacity", 0.3).stop(true, false).animate({
"opacity": "0"
},
300);
});
});
};
$('#top_goods_gallery.gallery').gallery();
$('#top_sale_gallery.gallery').gallery({
time: 5000,
direction:-1
});
});
</script>
</html>
te and use this in my project.
I'm trying to make a menu that contains 5 items/icons with the selected one being in the center. Clicking to the left or right of this centered icon, rotates the menu left or right, wrapping round the edges and moving whichever item was closest to the edge back in through the opposite one. Clicking on the centered item takes you to its linked URL.
The menu should also magnify in a way similar to the OS X dock except the magnification levels are set based on position not mouseover.
I've made a diagram which is easier to understand than my ramblings.
(source: yfrog.com)
I've managed to cobble together a simple jQuery version, where the items swap positions as needed, but can't figure out how to animate this movement, especially the wrap around the edges part, and change size based on position.
I'm guessing my code is probably not the best either :)
The HTML is as follows:
<div id="nav">
<div id="leftnav"></div>
<div id="rightnav"></div>
<div id="navblock1" class="navblock">
one
</div>
<div id="navblock2" class="navblock">
two
</div>
<div id="navblock3" class="navblock">
three
</div>
<div id="navblock4" class="navblock">
four
</div>
<div id="navblock5" class="navblock">
five
</div>
And the JS:
function rotateNav(direction) {
var change = (direction=='left')?(-1):(+1);
$('div.navblock').each(function() {
oldPos = parseInt($(this).attr('id').substr(9));
newPos = oldPos+change;
if (newPos == 0)
newPos = 5;
else if (newPos == 6)
newPos = 1;
$(this).attr('id','navblock'+newPos);
});
}
$(document).ready(function(){
$("#leftnav").click(function() {
rotateNav('right');
});
$("#rightnav").click(function() {
rotateNav('left');
});
});
All the .navblock elements are absolutely positionned. The #leftnav and #rightnav elements also and they have a higher z-index so float above the items/icons.
I've looked at various jQuery plugins but none seem close to what I need.
Instead of changing id attributes (which you really shouldn't do in the first place) you can change CSS classes and use jQuery UI's switchClass() method to animate the rotation.
You would also have to do a bit of clone()ing to make it look like the edge navblocks have rotated around to the other side of the widget and some queue()/dequeue()ing to handle multiple clicks.
Working Demo:
http://jsbin.com/ovemu (editable via http://jsbin.com/ovemu/edit)
Full Source:
JavaScript
function rotateNav(direction) {
if (direction === 'left') {
var change = 1;
$('.navblock5').clone()
.removeClass('navblock5')
.addClass('navblock0')
.appendTo('#nav');
}
else {
var change = -1;
$('.navblock1').clone()
.removeClass('navblock1')
.addClass('navblock6')
.appendTo('#nav');
}
$('div.navblock').each(function() {
var oldClassName = this.className.split(' ')[1],
oldPos = parseInt(oldClassName.substr(8)),
newPos = oldPos + change;
$(this).switchClass(
oldClassName,
'navblock'+newPos,
'fast',
function () {
var animated = $('.navblock:animated').length;
if (newPos === 6 || newPos === 0) {
$(this).remove();
}
if (animated === 1) {
$('#nav').dequeue();
}
}
);
});
}
$(document).ready(function(){
$("#leftnav").click(function() {
$('#nav').queue(function(){rotateNav('right');});
});
$("#rightnav").click(function() {
$('#nav').queue(function(){rotateNav('left');});
});
});
CSS
#nav {
width: 580px; height: 120px;
position: relative; left: 150px;
overflow: hidden;
}
.navblock {
height: 100px; width: 100px;
position: absolute; top: 10px; z-index: 50;
background-color: grey;
}
.navblock0 { left: -110px; }
.navblock1 { left: 10px; }
.navblock2 { left: 120px; }
.navblock3 { left: 230px; width: 120px; height: 120px; top: 0;}
.navblock4 { left: 360px; }
.navblock5 { left: 470px; }
.navblock6 { left: 590px; }
#leftnav, #rightnav {
position: absolute; z-index: 100; height: 120px; width: 228px;
}
#leftnav { left: 0; }
#rightnav { right: 0; }
/*Uncomment the following to help debug or see the inner workings */
/*
#nav { border: 1px solid green; overflow: visible; }
#leftnav, #rightnav { border: 1px solid blue; }
*/
HTML
<div id="nav">
<div id="leftnav"></div>
<div id="rightnav"></div>
<div class="navblock navblock1">one</div>
<div class="navblock navblock2">two</div>
<div class="navblock navblock3">three</div>
<div class="navblock navblock4">four</div>
<div class="navblock navblock5">five</div>
Instead of doing this yourself and wasting time on getting this to work properly I suggest you use existing solutions ones. Here a few pointers (I guess many more can be found by using google
jQuery: Mac-like Dock
Mac-like icon dock (v2)
MAC CSS Dock Menu
jQuery mimicking the OS X dock
Simple OSX-like dock with jQuery
iconDock jQuery Plugin
You seem to be on the right track. One issue is that this line
oldPos = parseInt($(this).attr('id').substr(9));
Should use 8 in the substr:
oldPos = parseInt($(this).attr('id').substr(8));