Chrome 20.x issue (bug?) with classes applied/removed at intervals via jQuery
Asked Answered
C

2

7

Here's a fun one for those of you who love to bang your heads against the computer keyboard.

Site: http://blduke.com.php53-27.dfw1-2.websitetestlink.com

Fun little jQuery thing going on right below the navigation here. It's actually a radial menu (plugin). The plugin includes functions that will trigger the rotation clockwise and counterclockwise, and by default the radial menu isn't shown. So I've got the code to initialize the radial menu, the code to show it immediately, and code to trigger the next rotation at intervals. Finally I've used the plugin's API to hook into the afterAnimation option to make sure that an "active" class is applied to the "active" menu item - I'm going to use it to do some fun CSS stuff, rotate some to the right of this graphic, etc. You can see that the "active" class on the list items right now just adds a red background.

This works absolutely perfectly in IE8+, Firefox, Safari, and versions 17.0-19.0 of Chrome. In Chrome 20.x it breaks in a weird way.

The active class still swaps to the appropriate list item when it should, but the browser is doing something weird, like delaying the rendering of the active class on the new item, or skipping it entirely at some points, or showing it on two items (the item it was last on, and the next one)

No script errors, and I'm baffled, as is the plugin dev. Anyone have any ideas, insight?

My Code:

jQuery(document).ready(function($) {
    $("#radial_container").radmenu({
        listClass: 'list', // the list class to look within for items
        itemClass: 'item', // the items - NOTE: the HTML inside the item is copied     into the menu item
        radius: 130, // radius in pixels
        animSpeed:400, // animation speed in millis
        centerX: 0, // the center x axis offset
        centerY: 0, // the center y axis offset
        angleOffset: 30, // in degrees,
        afterAnimation: function($m){ // after the animation triggers, grab the     "active" menu item (object) to recieve the "active" class
            $("#radial_container").radmenu(2); 
        }
   }).radmenu("show"); // Show the menu straight off, we don't need to trigger with a click

    setInterval(function() { // automatically rotate the menu at intervals
        $('#radial_container').radmenu('next');
    }, 4000);

});
Chemar answered 15/7, 2012 at 0:55 Comment(4)
I wish everybody would include such a detailed background, link and code with the proper tagging in their first questions as you did. On topic, my Chrome always has 2 classes active after the first time the position changes. Interesting.Speight
Thanks! I've gotten a lot of help from this site in the past, and the most helpful posts were definitely those that had solid background info :) Really? What tool did you use to see that? I was checking it out & watching the classes with Inspector, and it didn't seem to be duplicating. The plot thickens....Chemar
My bad, the class is not duplicated in fact, it just seems duplicated. When I mouseover the fake active element in the inspector, the display is instantly fixed. Seems like a Chrome bug, I'll debug it further. =]Speight
That was exactly my experience.Chemar
M
1

I edited your code slightly while testing locally:

setInterval(function() { // automatically rotate the menu at intervals
    $('.radial_div div').removeClass('active'); //add this line
    $('#radial_container').radmenu('next');
}, 4000);

Tested on Chrome 20 and FF16a.

This will ensure that all divs lose the active class when you call the rotation plugin, and it is properly added back to the top item when the afterAnimation function runs.


Then new issue seems quite hard to debug, as I can't get it to happen constantly. However, try this:

afterAnimation: function($m){ // after the animation triggers, grab the "active" menu item (object) to recieve the "active" class
    setTimeout(function() {
        $("#radial_container").radmenu(2);
    }, 0); 
}

This will ensure that the radmenu function is only called after the current function stack has finished processing, I watched it for a couple minutes and it didn't bug even once.

Also, if you want to start the top item with the active class already, you can just add:

$('.radial_div div:nth-child(3)').addClass('active');

Anywhere inside the .ready function.

Mckibben answered 15/7, 2012 at 1:53 Comment(5)
Awesome. That works! I'm going to accept this as the answer since the question was originally relating to the Chrome bug, but mad props to @Homeo for providing alternative code that could animate this without a plugin at all.Chemar
Oops, I have to take it back. So it works better - but check out the link again. When "Demolition" rotates from the top position, it sticks there - only!Chemar
Oh I saw it now. Working on that, even though it seems like an intermittent bug.Speight
@Chemar you meant that "Demolition" wasn't getting the active class when rotated to top, right? My new edit should fix that. Let me know if there are any other bugs. :PSpeight
Yes, thanks for being able to interpret my comment :) Your additions fixed it up nicely. Thanks so much for taking time to debug this! You're delightful :)Chemar
H
2

Why do you need a plugin for that? You are just animating top and left of three simple elements. Why not write it manually. It won't be longer that the sample code you provided for sure.

function setPosition(element, position) {
   var placements = [[100,100], [200, 200], [0, 200]] ; //for instance

   $(element).stop().animate({left: placements[position][0]+ 'px', top: placements[position][1] + 'px'});

   if (position == 0) { $(element).addClass('activeMenuItem');}
}

var state = 0;

function rotateMenu(direction) {
    state += direction;
    if (state < 0) state = 2;
    if (state > 2) state = 0;

    $('.menuItem').removeClass('activeMenuItem');

    setPosition('#item0', state  % 3);
    setPosition('#item1', (state + 1) % 3);
    setPosition('#item2', (state + 2) % 3);
}

That's it. rotateMenu(1) rotates to one direction while rotateMenu(-1) rotates it another direction.

Your menu items will have class="menuItem" and id="item".

Here is jsFiddle for a little demo.

Homeo answered 15/7, 2012 at 1:17 Comment(8)
Honestly? Because I'm something of a beginner :) jQuery plugins are a beginner's bread & butter! I'm learning, and I'll be dissecting your code next to figure out how YOU figured that out! Thanks! I'd like to know why Chrome is being wonky with this, but this might just be what I need to finish this project. I'll have to give it a test. I need the "selected" elements to get the special active class - can't tell for sure, is there a way to do that with this code?Chemar
Sure. Just added that. For basic things, it's better to fiddle with jQuery and figure things out on your own. It's more fun anyway in my opinion.Homeo
I love fiddling. This didn't seem basic to me (again - n00b!) That code looks gloriously simple. I'll figure out what it's doing and test it, and mark this as answered if it works out as a replacement. Thanks again!Chemar
--- edited --- thought I had a solution with the other answer but I spoke too quickly :) I'll be trying this after all!Chemar
I'm +1'ing your answer too as you did a good job rewriting it from scratch. =] I just think it isn't quite needed to rewrite the whole function when it's working fine already for the most part.Speight
There are still some bugs in your code too, you call placement twice which is undefined (should be placements), and fixing that brings a placements[position] is undefined here... Here's the fiddle I'm testing jsfiddle.net/ult_combo/2ZTbCSpeight
Woah awesome function wrote from the beginning. I'd +1 it again if I could for the psychedelic effect when you click non-stop in the same button, awesome. =]Speight
Should also note that px is unneeded when passing numeric px values to jQuery, just tidbits.Speight
M
1

I edited your code slightly while testing locally:

setInterval(function() { // automatically rotate the menu at intervals
    $('.radial_div div').removeClass('active'); //add this line
    $('#radial_container').radmenu('next');
}, 4000);

Tested on Chrome 20 and FF16a.

This will ensure that all divs lose the active class when you call the rotation plugin, and it is properly added back to the top item when the afterAnimation function runs.


Then new issue seems quite hard to debug, as I can't get it to happen constantly. However, try this:

afterAnimation: function($m){ // after the animation triggers, grab the "active" menu item (object) to recieve the "active" class
    setTimeout(function() {
        $("#radial_container").radmenu(2);
    }, 0); 
}

This will ensure that the radmenu function is only called after the current function stack has finished processing, I watched it for a couple minutes and it didn't bug even once.

Also, if you want to start the top item with the active class already, you can just add:

$('.radial_div div:nth-child(3)').addClass('active');

Anywhere inside the .ready function.

Mckibben answered 15/7, 2012 at 1:53 Comment(5)
Awesome. That works! I'm going to accept this as the answer since the question was originally relating to the Chrome bug, but mad props to @Homeo for providing alternative code that could animate this without a plugin at all.Chemar
Oops, I have to take it back. So it works better - but check out the link again. When "Demolition" rotates from the top position, it sticks there - only!Chemar
Oh I saw it now. Working on that, even though it seems like an intermittent bug.Speight
@Chemar you meant that "Demolition" wasn't getting the active class when rotated to top, right? My new edit should fix that. Let me know if there are any other bugs. :PSpeight
Yes, thanks for being able to interpret my comment :) Your additions fixed it up nicely. Thanks so much for taking time to debug this! You're delightful :)Chemar

© 2022 - 2024 — McMap. All rights reserved.