PDA

View Full Version : Step Carousel Viewer - script crashing



increatie
10-13-2009, 01:56 PM
1) Script Title: Step Carousel Viewer

2) Script URL (on DD): http://www.dynamicdrive.com/dynamicindex4/stepcarousel.htm

3) Describe problem: The carousel works like a charm but when I am accessing it externally and do that a bit too fast, the script crashes.

If you take a look at : http://www.increatie.nl/new/default.aspx?PageID=15 you will see that the submenu on the left accesses (on the onmouseover event) the carousel with good effect as long as you move your mouse slowly.
As soon as you rush over the items the carousel stops functioning.

Any ideas how to solve this behavior?

Regards,

Vincent Fabris
INcreatie

jscheuer1
10-13-2009, 02:59 PM
An obvious solution would be to change the mouseover activators to click activated. Other than that, there is probably a problem with the script in that it cannot recover from being given new instructions for movement while still moving from a previous instruction. A look at the code may turn up a fix for this, but it might be quite complicated to work out.


A fix for this might be to modify the stepBy function in the stepcarousel.js file (additions highlighted):


stepBy:function(galleryid, steps, isauto){
var config=stepcarousel.configholder[galleryid]
if (typeof config=="undefined"){
//alert("There's an error with your set up of Carousel Viewer \""+galleryid+ "\"!")
return
}
if(config.moving){return;}
config.moving = true;
if (!isauto) //if stepBy() function isn't called by autorotate() function
stepcarousel.stopautostep(config)
var direction=(steps>0)? 'forward' : 'back' //If "steps" is negative, that means backwards
var pindex=config.currentpanel+steps //index of panel to stop at
if (config.panelbehavior.wraparound==false){ //if carousel viewer should stop at first or last panel (instead of wrap back or forth)
pindex=(direction=="back" && pindex<=0)? 0 : (direction=="forward")? Math.min(pindex, config.lastvisiblepanel) : pindex
if (config.defaultbuttons.enable==true){ //if default nav buttons are enabled, fade them in and out depending on if at start or end of carousel
stepcarousel.fadebuttons(config, pindex)
}
}
else{ //else, for normal stepBy behavior
if (pindex>config.lastvisiblepanel && direction=="forward"){
//if destination pindex is greater than last visible panel, yet we're currently not at the end of the carousel yet
pindex=(config.currentpanel<config.lastvisiblepanel)? config.lastvisiblepanel : 0
}
else if (pindex<0 && direction=="back"){
//if destination pindex is less than 0, yet we're currently not at the beginning of the carousel yet
pindex=(config.currentpanel>0)? 0 : config.lastvisiblepanel /*wrap around left*/
}
}
var endpoint=config.paneloffsets[pindex]+(pindex==0? 0 : config.beltoffset) //left distance for Belt DIV to travel to
if (pindex==0 && direction=='forward' || config.currentpanel==0 && direction=='back' && config.panelbehavior.wraparound==true){ //decide whether to apply "push pull" effect
config.$belt.animate({left: -config.paneloffsets[config.currentpanel]-(direction=='forward'? 100 : -30)+'px'}, 'normal', function(){
config.$belt.animate({left: -endpoint+'px'}, config.panelbehavior.speed, function(){config.onslideaction(this)})
})
}
else
config.$belt.animate({left: -endpoint+'px'}, config.panelbehavior.speed, function(){config.onslideaction(this)})
config.currentpanel=pindex
this.statusreport(galleryid)
config.moving = false;
},

Untested, but should work. Be sure to scroll the code block down to see the third added line near the end of the function.

increatie
10-14-2009, 06:37 AM
Hi John,

Thank you for your swifr reply but unfortunately that didn't solve the issue...
Your logic makes sense but after I found it didn't solve, I started tracing the pindex value and displaying it in a div above the caroussel...

I am doing the trace like this(rightly below the setting of the pindex)
var el = document.getElementById('output');
el.innerHTML = pindex;

Now you can still 'lock' the caroussel by moving too fast but the pindex is still being properly set and displayed on the mouse-over events.

I think this shows that the method still gets fired but for some (other) reason the caroussel doesn't move. Any ideas?

By the way, I have to use the onmouseover event because the click event is needed for the link to another page.

Regards,

Vincent

jscheuer1
10-14-2009, 09:51 AM
I see. Well, for one thing I attacked the wrong function. I went after stepBy, I should have gone after stepTo. I also didn't take into account that there is a sort of timeout situation created by the animation, so that even if I had altered the correct function, the carousel could still be moving when my new property was set to false again, thus allowing multiple movements to still collide with each other.

I have arrived at a solution. It isn't ideal because now a situation can arise where the cursor ends up over one of the menu items, but a different image and text are displayed in the viewer area. But at least it won't crash.

To implement this, return to the script as it was before I made any modification to it, then replace the stepTo function with this one:


stepTo:function(galleryid, pindex){ /*User entered pindex starts at 1 for intuitiveness. Internally pindex still starts at 0 */
var config=stepcarousel.configholder[galleryid]
if (typeof config=="undefined"){
//alert("There's an error with your set up of Carousel Viewer \""+galleryid+ "\"!")
return
}
if(config.moving){return;}
config.moving = true;
stepcarousel.stopautostep(config)
var pindex=Math.min(pindex-1, config.paneloffsets.length-1)
var endpoint=config.paneloffsets[pindex]+(pindex==0? 0 : config.beltoffset)
if (config.panelbehavior.wraparound==false && config.defaultbuttons.enable==true){ //if carousel viewer should stop at first or last panel (instead of wrap back or forth)
this.fadebuttons(config, pindex)
}
config.$belt.animate({left: -endpoint+'px'}, config.panelbehavior.speed, function(){config.moving = false;config.onslideaction(this)})
config.currentpanel=pindex
this.statusreport(galleryid)
},

Once again there are three lines where I've made additions, scroll the code block to the right to see the third.

I will have a look at possibly overcoming the one drawback of this solution and report back if I find a way to do that.

jscheuer1
10-14-2009, 10:06 AM
OK, this seems to be about the best you can get. If there is a lot of rapid movement over the menu, things can get a little delayed, but at least there will be no crash, and the content in the viewer area will catch up to the proper display for wherever the mouse cursor ends up or hovers last on the menu. All additions to the original function are highlighted, including those made in my previous post.


stepTo:function(galleryid, pindex){ /*User entered pindex starts at 1 for intuitiveness. Internally pindex still starts at 0 */
var config=stepcarousel.configholder[galleryid]
if (typeof config=="undefined"){
//alert("There's an error with your set up of Carousel Viewer \""+galleryid+ "\"!")
return
}
if(config.movTimer){
clearTimeout(config.movTimer);
}
if(config.moving){
config.movTimer = setTimeout(function(){stepcarousel.stepTo(galleryid, pindex);}, 300);
return;
}
config.moving = true;
stepcarousel.stopautostep(config)
var pindex=Math.min(pindex-1, config.paneloffsets.length-1)
var endpoint=config.paneloffsets[pindex]+(pindex==0? 0 : config.beltoffset)
if (config.panelbehavior.wraparound==false && config.defaultbuttons.enable==true){ //if carousel viewer should stop at first or last panel (instead of wrap back or forth)
this.fadebuttons(config, pindex)
}
config.$belt.animate({left: -endpoint+'px'}, config.panelbehavior.speed, function(){config.moving = false;config.onslideaction(this)})
config.currentpanel=pindex
this.statusreport(galleryid)
},

One thing I notice though is that the menu items can get highlighted without affecting the viewer, and that they can get clicked on without navigating to the page. This is because the list item (li tag) gets some sort of highlighting which extends it when hovered, but when this highlighted area is hovered or clicked, nothing else happens. I'd move the onmouseover events to the li tags, and add onclick events to them that would activate their links as well. Example:


<li class="menuli" onmouseover="stepcarousel.stepTo('mygallery', 1);" onclick="location = this.firstChild.href;"><a href="default.aspx?PageID=65" title="" class="list">Moke</a></li>

Also, since they are now basically links themselves, the class selector .menuli in your stylesheet should be given the following style:


cursor: pointer;

increatie
10-14-2009, 10:54 AM
Great!

Works like a charm now :)

Thank you for the other points as well... I noticed them before as well, but we're currently building the site so we're far from done here :)

Thankx a lot John!

Kind regards,

Vincent Fabris
INcreatie

jscheuer1
10-14-2009, 01:24 PM
A better way to deal with those other issues would be to remove the events from the list and links entirely, use this style (though some IE browsers may have a problem with this style, an alternate may need to be found for them):


.menuli a {
display: block;
width: 100%;
height: 100%;
}

This will better take care of the links because they will now cover the entire area of their parent li element.

And for the mouseover events, add this code (highlighted) as shown:


<script type="text/javascript">
stepcarousel.setup({
galleryid: 'mygallery', //id of carousel DIV
beltclass: 'belt', //class of inner "belt" DIV containing all the panel DIVs
panelclass: 'panel', //class of panel DIVs each holding content
autostep: { enable: false, moveby: 1, pause: 3000 },
panelbehavior: { speed: 500, wraparound: false, persist: true },
defaultbuttons: { enable: true, moveby: 1, leftnav: ['i/arrow-left.png', -8, 145], rightnav: ['i/arrow-right.png', -34, 145] },
statusvars: ['statusA', 'statusB', 'statusC'], //register 3 variables that contain current panel (start), current panel (last), and total panels
contenttype: ['inline'], //content setting ['inline'] or ['external', 'path_to_external_file']
oninit: function() {
contentcontainer = document.getElementById('Text') //reference DIV used to contain related content
},
onslide: function() {
//Update DIV with this panel's related content (notice imageA-1 as the array index, as imageA starts at 1, while array at 0
contentcontainer.innerHTML = contentarray[statusA - 1]
}
}
)
jQuery(function($){
$('.menuli').each(function(i){
$(this).bind('mouseover', function(){
stepcarousel.stepTo('mygallery', i + 1);
});
});
});
</script>