I'm using Swiper API to let the user swipe across multiple pages on my HTML5/JS/CSS website.
I initialized the swiper (plase note I'm using Framework7 which includes Swiper API as an internal module, the app object represent the Framework7 instance:
var swiper = app.swiper.create('#swiper', {
speed: 200,
spaceBetween: 0,
initialSlide: 0,
loop: true,
pagination: {
el: '.swiper-pagination',
type: 'bullets',
},
autoHeight: true,
});
I also have three slides on my HTML:
<div class="swiper-container" id="swiper">
<div class="swiper-wrapper">
<div class="swiper-slide">Slide 1</div>
<div class="swiper-slide">Slide 2</div>
<div class="swiper-slide">Slide 3</div>
</div>
<div class="swiper-pagination"></div>
</div>
I wrote a listener to listen for page changes: each time the user swipes to the next page, the transitionEnd event is fired
swiper.on("transitionEnd", function(e){
var slideIndex = swiper.activeIndex;
console.log("I'm on slide no: "+slideIndex);
});
When I try to retrieve the current slide index (swiper.activeIndex) I get very weird results: I would expect to get a number, either 0, 1 or 2 (the current page index).
If I don't wrap around I get 1,2,3 (ok, not 0-based, perfectly fine I'll add a -1). If I wrap around (Swiper seamlessly swipes in loop, wrapping around the pages) I also get 0, and 4 as indexes and I don't know why.
The documentation says that in loop mode (loop: true) the active page index works as follow:
Index number of currently active slide
Note, that in loop mode active index value will be always shifted on a
number of looped/duplicated slides
Still don't understand that sentence. "shifted on a number of looped slides"?
Inspecting the HTML I can see that Swiper API creates extra "duplicates" slides at the far left and right of the "real" slide sequence, to create the effect of a seamless loop across pages.
But if effectively I just have 3 pages, why I also get indexes 0 and 4 instead of just 1,2,3? (page1 = 1, page2 = 2, page3 = 3)?
With loop enabled, swiper duplicates the first slide to the end, and the last Slide before the first too keep the animation in flow.
3 Pages + 2 Duplicates = 5 Pages (index 0-4)
With swiper.activeIndex you are accessing the virtual slides, just use swiper.realIndex for the real index.
Related
When moving back through the loop using the "previous" navigation button the slides seem to jump from last to first. Issue seems to happen on all platforms.
Moving forward using navigation works as expected, and dragging works as expected.
I have done a fiddle based off the "Centered Slides + Auto Slides Per View" demo on the Swiper website, adding only the navigation html
<!-- Add Arrows -->
<div class="swiper-button-next"></div>
<div class="swiper-button-prev"></div>
and the options
loop: true,
loopedSlides: 10,
roundLengths: true,
navigation: {
nextEl: '.swiper-button-next',
prevEl: '.swiper-button-prev',
},
JSFiddle here: https://jsfiddle.net/MatraSimca/L063jo3x/17/
In the production site I'm working on I'm using fixed width slides and the issue only seems to occur when adding
roundLengths: true,
With the percentage based widths in the demo fiddle the issue occurs with or without the roundLengths option. Any pointers appreciated...
loop functionality is duplicating only DOM nodes, meaning that your duplicated slides for the loop don't have their JS code appended as well, only the rendered result.
I spent 2 days trying to figure this out, so by using the original Swiper's methods and events, I came to a semi-infinite-loop feature:
add the following to your swiper's config
loop: true,
loopedSlides: 1,
on: {
slideChange: function () {
let lastVisibleItem = this.realIndex + this.params.slidesPerView
let slidesLength = this.slides.length - 2
let lastVisibleIndex = this.realIndex + this.params.slidesPerView
// if swiper reaches the end of displayed items, goToNext redirects swiper to the start
if (lastVisibleItem > slidesLength) {
this.slideTo(1)
}
// if swiper wants to go before the first item, then forward swiper to the last item
if (lastVisibleIndex >= this.slides.length) {
this.slideTo((slidesLength - this.params.slidesPerView) + 1)
}
}
}
I use a Bootstrap carousel to cycle through a series of D3 charts and tables, showing performance data for a specific team. After a complete cycle, the team input is toggled and the charts are reloaded for the newly-selected team.
The issue that I'm running into is that the data can take as long as 20 seconds to get to the client. As a result, the carousel often cycles before the first slide can load.
What I figured I'd do is wait until the data is available to start the carousel in the first place, and then essentially pause it at the end of a cycle, restarting it once the new data has loaded. To do so I'm calling $('.carousel').carousel({ interval: '10000' }) when the data becomes available. This works fine on initial page load. However I need to pause the carousel before requesting data for the next team, and I can't seem to figure out how to do so. It appears as though setting $('.carousel').carousel({ interval: false }) has no effect.
Something to keep in mind is that I'd like to retain the carousel's manual slide controls and 'hover' pause behavior in between cycles.
Any help is appreciated.
UPDATE (sample code):
Original technique:
Markup:
<div
id="carousel"
class="carousel slide"
data-ride="carousel"
data-interval="30000"
data-pause="hover"
>
<div class="carousel-inner">
<div class="item active">
...
Javascript:
Upon completion of a cycle:
toggleTeams()
Session.set 'loading', true // show loading overlay
After each data reload:
Session.set 'loading', true // show loading overlay
if ticketSubscriptionHandle.ready() // wait for data to be ready
Session.set 'loading', false // hide loading overlay
drawCharts() // redraw charts
Latest technique:
Markup:
<div
id="carousel"
class="carousel slide"
>
<div class="carousel-inner">
<div class="item active">
...
Javascript:
Upon completion of a cycle:
carousel = $('.carousel')
carousel.detach() //remove the carousel from the DOM to stop the cycle while data loads
toggleTeams()
Session.set 'loading', true // show loading overlay
After each data reload:
Session.set 'loading', true // show loading overlay
if ticketSubscriptionHandle.ready() // wait for data to be ready
if isFirstLoad
$('.carousel').carousel(interval: '2000') // start the carousel
isFirstLoad = false
else
$('.container-fluid').append(carousel) // drop the carousel back in
Session.set 'loading', false // hide loading overlay
drawCharts() // redraw charts
Even with this technique it appears as though the carousel is changing after I remove it from the DOM. If I throw a debugger in at removal I can see that the .active slide is slide 1 of 5, yet when it gets reinserted it's at slide 2, 3, or sometimes 4. This carousel is something else...
Look this (carousel \ Methods)
.carousel('cycle')
Cycles through the carousel items from left to right.
.carousel('pause')
Stops the carousel from cycling through items.
.carousel(number)
Cycles the carousel to a particular frame (0 based, similar to an array).
.carousel('prev')
Cycles to the previous item.
.carousel('next')
Cycles to the next item.
Stop:
$("#carouselExample").attr('data-interval', '0');
Start:
$("#carouselExample").attr('data-interval', '9000');
I'm currently making a website in Bootstrap 3.0 with a carousel.
In mobile mode (xs) I have 4 items in the carousel, but when it gets to tablet size (sm or md) the client wants to drop this to just 2 items instead of 4.
Hiding the indicators is easy enough, you can use hidden-sm to get rid of 2 of the dots, and I've also added hidden-sm to the items themselves, but the JS that controls the carousel ignored the fact that the items are set to display: none, and it scrolls through them anyway.
Does anyone know of a way to get Bootstrap to ignore items at certain responsive breakpoints?
I had a similar problem, but needed to be able to dynamically change the number of slides. To keep it simple, I chose to base it on the visibility of the carousel indicators. I added the following to bootstrap.js, just after the variable declarations inside Carousel.prototype.slide():
var $nextIndicator;
if (this.$indicators.length) {
var iChildren = this.$indicators.children();
var i=0;
while (($nextIndicator = $(iChildren[this.getItemIndex($next)])) && !$nextIndicator.is(':visible') && i<iChildren.length) {
$next = $next[type]();
if (!$next.length) {
if (!this.options.wrap) return
$next = this.$element.find('.item')[fallback]()
}
i++;
}
}
To remove slides I put the following in my own code:
$indicatorsToRemove.hide();
// don't leave user on a page that got removed:
if ($indicatorsToRemove.filter('.active').length) {
$('#carousel').carousel('next');
}
To add them back:
$indicatorsToAdd.show();
THE SITUATION:
I am using for my slideshow the Slider Revolution plugin.
I need to set different times (duration) for the images displayed.
For example the first image i need to display for just 2 seconds, while the second image for 7 seconds.
THE QUESTION:
How can i set the time that last a single item?
Is it possible?
THE CODE:
In the js function that initialize the plugin, there are these setting:
delay:9000,
and changing it, it is possible to set the duration, but will regard all the items.
This is the js function:
initRevolutionSlider: function () {
var tpj=jQuery;
tpj(document).ready(function() {
if (tpj.fn.cssOriginal!=undefined)
tpj.fn.css = tpj.fn.cssOriginal;
var api = tpj('.fullwidthbanner').revolution(
{
delay:9000,
startwidth:960,
startheight:250,
onHoverStop:"off", // Stop Banner Timet at Hover on Slide on/off
thumbWidth:100, // Thumb With and Height and Amount (only if navigation Tyope set to thumb !)
thumbHeight:50,
thumbAmount:3,
hideThumbs:1,
navigationType:"bullet", // bullet, thumb, none
navigationArrows:"solo", // nexttobullets, solo (old name verticalcentered), none
navigationStyle:"round-old", // round,square,navbar,round-old,square-old,navbar-old, or any from the list in the docu (choose between 50+ different item), custom
navigationHAlign:"center", // Vertical Align top,center,bottom
navigationVAlign:"bottom", // Horizontal Align left,center,right
navigationHOffset:30,
navigationVOffset:20,
soloArrowLeftHalign:"left",
soloArrowLeftValign:"center",
soloArrowLeftHOffset:20,
soloArrowLeftVOffset:0,
soloArrowRightHalign:"right",
soloArrowRightValign:"center",
soloArrowRightHOffset:20,
soloArrowRightVOffset:0,
touchenabled:"on", // Enable Swipe Function : on/off
stopAtSlide:-1, // Stop Timer if Slide "x" has been Reached. If stopAfterLoops set to 0, then it stops already in the first Loop at slide X which defined. -1 means do not stop at any slide. stopAfterLoops has no sinn in this case.
stopAfterLoops:-1, // Stop Timer if All slides has been played "x" times. IT will stop at THe slide which is defined via stopAtSlide:x, if set to -1 slide never stop automatic
hideCaptionAtLimit:0, // It Defines if a caption should be shown under a Screen Resolution ( Basod on The Width of Browser)
hideAllCaptionAtLilmit:0, // Hide all The Captions if Width of Browser is less then this value
hideSliderAtLimit:0, // Hide the whole slider, and stop also functions if Width of Browser is less than this value
fullWidth:"on",
shadow:0 //0 = no Shadow, 1,2,3 = 3 Different Art of Shadows - (No Shadow in Fullwidth Version !)
});
This is the HTML for a single item:
<div class="fullwidthbanner">
<li data-transition="3dcurtain-vertical" data-slotamount="10" data-speed="100" data-masterspeed="300" data-thumb="assets/img/sliders/revolution/thumbs/thumb1.jpg">
<!-- THE MAIN IMAGE IN THE FIRST SLIDE -->
<img src="img/slideshow/1.jpg">
</li>
</div>
In this case data-speed and data-masterspeed regards the time of the transition, not the time that last the item.
Someone knows perhaps how this can be achieved?
It has to be done in the HTML or perhaps in the js function ?
Thank you very much!
According to this documentation [dead link removed], pretty sure it is for your plugin, it provides a data-delay config for each slide.
See the docs under the "02 Slider items" header in the page.
<div class="fullwidthbanner">
<li data-transition="3dcurtain-vertical"
data-delay="2000"
data-slotamount="10"
data-speed="100"
data-masterspeed="300"
data-thumb="assets/img/sliders/revolution/thumbs/thumb1.jpg">
<!-- THE MAIN IMAGE IN THE FIRST SLIDE -->
<img src="img/slideshow/1.jpg">
</li>
<li data-transition="3dcurtain-vertical"
data-delay="7000"
data-slotamount="10"
data-speed="100"
data-masterspeed="300"
data-thumb="assets/img/sliders/revolution/thumbs/thumb2.jpg">
<!-- THE MAIN IMAGE IN THE SECOND SLIDE -->
<img src="img/slideshow/2.jpg">
</li>
</div>
I am using Flexslider 2.0 with the startAt option on the last slide.
This seems to mess up the directional navigation.
Anybody had this issue before and knows how to solve it?
The code I am using with nothing really special:
$(".period-slides").flexslider({
animation: "slide",
animationLoop: false,
itemWidth: 265,
minItems: 4,
maxItems: 4,
controlNav: false,
directionNav: true,
prevText: "\ue75d",
nextText: "\ue75e"
startAt: 7
});
EDIT: Html added
<div class="period-slides">
<ul class="slides">
<li class="slide"><!-- repeated 8 times -->
<div class="period-overview">
<p>Some Content</p>
</div>
</li>
</ul>
</div>
EDIT: It doesn't seem to have a proper indication of at what position in currently is, seems like in the navigation the current position is the first slide. So I when setting the startAt it doesn't set the navigation properly.
Based on that HTML in your edit, you have 8 items in total which will be split into two slides of four.
I think the problem you are having is that setting startAt to 7 is too high - you only have two slides, so the index will need to be either 1 or 0.
When I set startAt to 7 the slider initially appeared blank and I had to navigate backward to get the final slide to appear. Setting startAt to 1 or 0 caused the correct slide to be displayed initially.