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');
Related
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.
I currently have this:
$(window).load ->
$('#image-gallery').lightSlider
gallery: true
item: 1
thumbItem: 7
slideMargin: 0
loop: true
But the issue is that my lightSlider is loading in the wrong position when the page is not fully loaded. After page loads completely, the slider fixes itself.
How do I make sure that my loader image shows first and then it will load this snippet after the slider is ready?
EDIT
Sorry, I meant I wanted to show a loading gif before the image is shown
#pre-loading
= image_tag "ajax-loader.gif"
%ul#image-gallery
- #go.go_images.each do |image|
%li{ data: { thumb: image.photo_url(:small), src: image.photo_url(:small)} }
= image_tag image.photo_url(:large)
So I'm trying to show the #pre-loading div prior to showing %ul#image-gallery. My coffeescript is correct, but the issue is that the slider is loading too fast, and it's not in the right position when it loads. I want to hide the slider, show the preloader, and when the slider is fully loaded after the entire page is completely done loading, then show the slider.
http://jsfiddle.net/czt0mycw/
<body>
<div id="hold_divs">hold divs
<div id="div1">div1</div>
<div id="div2">div2</div>
<div id="div3">div3</div>
<div id="div4">div4</div>
</div>
</body>
This is my first time building a jquery slider and it is exhibiting the strangest behavior. When the page first loads, it slides(automatically) the contents(my 4 divs stacked on top of one another) to the right successfully. But after a full slide show is completed, the slider no longer displays div1(the div with the red background). Instead, it skips(I believe that's whats happening) and shows the parent div("hold_divs").
When I was debugging, I altered the code to slide in only 2 divs, and a similar error occurred. This time, the two divs slid correctly only once (when the page is first loaded). After the first slide show completed successfully, it displayed the first of the 2 divs, but the 2nd div in the was not displayed; the 3rd div in the array was. O.o
http://jsfiddle.net/czt0mycw/1/
You need to reset the divs on the next iteration of the interval. Change:
setInterval(function()
{
var divs=[$("#div4"),$("#div3"),$("#div2"),$("#div1")];
var width=divs[x].width();
divs[x].stop().animate({right:"100%"},"slow");
x+=1;
if(x==4)
{
$("#div4,#div3,#div2,#div1").css("right",0);
x=0;
}
},3000);
to
setInterval(function()
{
if(x==4)
{
$("#div4,#div3,#div2,#div1").css("right",0);
x=0;
return;
}
var divs=[$("#div4"),$("#div3"),$("#div2"),$("#div1")];
var width=divs[x].width();
divs[x].stop().animate({right:"100%"},"slow");
x+=1;
},3000);
What's happening is that you're resetting the divs immediately after you start the animation for the 4th div. Instead, you want to reset the divs immediately before you start the animation again for the 1st div.
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 setting up a site for a photographer. It should be built using the Bootstrap 3 framework, and he wants to have a masonry with over 400 images on one page. For this to work LazyLoad is a must. I have now spent several days trying to get LazyLoad to work with Desandros Masonry but with no success..
I've tried all of the examples that one finds googling, but most posts/sites/forums just redirects you, or have copied this stackoverflow answer:
Combining LazyLoad and Jquery Masonry
I've tried both methods but unfortunately I get nothing but grey hair..... :(
Here is a simplified live version of the page im working on:
http://nr.x10.mx
In this example I have added a fade-in on page-load, but left the LazyLoad out since I can get it to work.
And here you have a FIDDLE of the following
var container = document.querySelector('#ms-container');
imagesLoaded( container, function()
{
var msnry = new Masonry(container,
{ itemSelector: '.ms-item',
columnWidth: '.ms-item',});
});
You can also download the whole pack here, including the jquery.lazyload.js HERE
Any help would be highly appreciated
UPDATE
Here you can have 4 different examples of the different problems that occur.
I also found to my joy that the Bootstrap .img-responsive class is interfering with LazyLoad.
1 - Masonry without LazyLoad
2 - Masonry and Lazyload - Masonry breaks down and LazyLoad has no effect
3 - LazyLoad without Masonry - LazyLoad has no effect
4 - LazyLoad without Masonry and Bootsrap "img-responsive" removed
5 - Masonry & LazyLoad using first method of SO answer mentioned above
6 - Masonry & LazyLoad using second method of SO answer mentioned above Both of the last ones gives the following error: [Error] TypeError: 'undefined' is not a function (evaluating '$container.imagesLoaded')
global code (5.html, line 110)
Updated zip HERE
Again, any asisstance would be highly appreciated, thank you
I made your 5.html work by using the javascript files of the fiddle present on the SO link you posted, answered by Nathan Do. So you probably just had bad versions of the scripts.
The scripts linked on that page are: http://cdn.jsdelivr.net/masonry/2.1.08/jquery.masonry.min.js and http://cdn.jsdelivr.net/jquery.lazyload/1.8.4/jquery.lazyload.js
Here's your original fiddle updated with that page's method: http://jsfiddle.net/L9RLe/
In your case, though you are creating masonry and adding lazyload effect, the images get overlapped.
You need to follow steps as :
Create Dynamic HTML structure for images along with their respective aspect ratio height and width. Note: images should have the required attributes for applying lazy load effect i.e. class="lazy" data-original="actual image url" and src="dummy imageurl".
Apply lazy load effect.
Then create Masonry.
Lets have an example :
Suppose I am having a javascript array with some image related data as,
var gallery_itemList= [
{url: "images/example1.jpg", width:"1170", height:"460"},
{url: "images/example2.jpg", width:"800", height:"320"},
{url: "images/example3.jpg", width:"1200", height:"870"}];
And below prototype for creating dynamic html, applying lazyload effect and creating Masonry effect as :
var masonryGallery = {
gallery :'', // gallery to create
genarateGallery : function() {
// generate each item html
var inHTML="", i;
for(i=0;i<gallery_itemList.length;i++){
var iWidth, iHeight, fHeight=0;
iWidth=parseInt(gallery_itemList[i].width);
iHeight=parseInt(gallery_itemList[i].height);
fHeight = Math.round((iHeight*300)/iWidth);
inHTML+='<div class="item" style="height:'+fHeight+'px">';
inHTML+='<img class="lazy" src="images/loading.gif" data-original="'+gallery_itemList[i].url+'"/>';
inHTML+='</div>';
}
//add generated html to gallery
$(masonryGallery.gallery).append(inHTML);
},
applyLazyload : function(){
$("img.lazy").lazyload();
},
createMasonry : function(){
// create Masonry
$(masonryGallery.gallery).masonry({
columnWidth: 350,
itemSelector: '.item',
isFitWidth: true,
isAnimated: !Modernizr.csstransitions
}).imagesLoaded(function() {
$(this).masonry('reload');
});
},
init : function(givenGallery) {
masonryGallery.gallery = givenGallery; // set gallery
masonryGallery.genarateGallery(); // generate gallery html
masonryGallery.applyLazyload(); // apply lazyload effect
masonryGallery.createMasonry(); // apply masonry effect
}
};
/* Gallery Intialisation */
(function(){masonryGallery.init('div#content');})();
If you have the problem images get overlapped, I found the solution at the site below, although it is in Japanese.
http://www.webdesignleaves.com/wp/jquery/1340/
The point is use following;
$('img.lazy').load(function(){ ... })
HTML
<div id="works_list">
<div class="work_item">
<img class="lazy" src="images/dummy.gif" data-original="images/works/thumb/001.jpg" alt="">
<p>title 1</p>
</div><!-- end of .work_item-->
<div class="work_item">
<img class="lazy" src="images/dummy.gif" data-original="images/works/thumb/002.jpg" alt="">
<p>title 2</p>
</div><!-- end of .work_item-->
....
</div><!-- end of #works_list -->
jQuery
$("img.lazy").lazyload({
effect: 'fadeIn',
effectspeed: 1000,
threshold: 200
});
$('img.lazy').load(function() {
masonry_update();
});
function masonry_update() {
var $works_list = $('#works_list');
$works_list.imagesLoaded(function(){
$works_list.masonry({
itemSelector: '.work_item',
isFitWidth: true,
columnWidth: 160
});
});
}
Just want to contribute my solution to this thorny problem.
Basically you need to call masonry's layout() function every time an image is lazyloaded, because that's when you know what it's dimensions are going to be. So you setup lazyload's load() function to call masonry.layout(). This can cause a new problem, because on your initial page load, all of your images will have a zero or near-zero height (depending on your css), and thus stack up in the top of the viewport. When you initialize lazyload, it will see all these images in the viewport, and try to load them all at once. This causes you to download tons of images, and even worse, calls masonry dozens or hundreds of times. Not very speedy.
My solution is to force a minimum height on unloaded images until they are lazyloaded. This restricts the number of images that will be found in the viewport initially, limiting the number of lazyload and masonry calls to a reasonable amount.
Once an image is loaded, you remove the .unloaded class in order to deconstrict the height and allow it to conform to the height of the image.
HTML
<div id="masonry-container">
<div class="masonry-item unloaded"><img class="lazy" data-original="image.jpg"></div>
<!-- Repeat as needed -->
</div>
CSS
.masonry-item {
width: 33.3%; // I'm doing a 3-column masonry layout
}
.unloaded {
min-height: 200px;
// set a minimum default height for image containers
// this prevents too many images from appearing in the viewport
// thus causing lazy load to load too many images at once
// we will use the lazyload .load() callback to remove this fixed
}
JS
$( document ).ready(function() {
// Initialize Masonry
var container = document.querySelector('#masonry-container');
var msnry = new Masonry( container, { transitionDuration: 0 } );
msnry.layout(); // run masonry for first time
function doMasonry() { msnry.layout(); } // gives us a function handler to call later with window.setTimeout()
// Initialize lazyload
$("img.lazy").lazyload({
effect : "fadeIn", // optional
load : function() {
$(this).parent().removeClass("unloaded"); // select the div containing the image and remove the "unloaded" class, thus deconstricting the min-height
window.setTimeout(doMasonry,100); // trigger masonry again with a 100 ms delay, if we do it too soon, the image may not have loaded, and masonry will layout with the wrong image dimensions (this might be a bit of a hacky way to do it)
}
});
});