Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>One more answer, hopefully my last one...</p> <p>Unfortunately, John Resig's syncAnimate method is not quite up to snuff for the accordion-type animation I want to do. While it works great on Firefox, I couldn't get it working smoothly on IE or Safari.</p> <p>With that said, I decided to bite the bullet and write my own animation engine that does simple parallel animations. The class-code uses jquery functions but is not a jquery plugin. Also, I've only set it up to do size/position animations, which is all I need.</p> <pre><code>ParallelAnimations = function(animations, opts){ this.init(animations, opts); }; $.extend(ParallelAnimations.prototype, { options: { duration: 250 }, rules: {}, init: function(animations, opts){ // Overwrite the default options $.extend(this.options, opts); // Create a set of rules to follow in our animation for(var i in animations){ this.rules[i] = { element: animations[i].element, changes: new Array() }; for(var style in animations[i].styles){ // Calculate the start and end point values for the given style change var from = this.parse_style_value(animations[i].element, style, ""); var to = this.parse_style_value(animations[i].element, style, animations[i].styles[style]); this.rules[i].changes.push({ from: from, to: to, style: style }); } } this.start() }, /* * Does some parsing of the given and real style values * Allows for pixel and percentage-based animations */ parse_style_value: function(element, style, given_value){ var real_value = element.css(style); if(given_value.indexOf("px") != -1){ return { amount: given_value.substring(0, (given_value.length - 2)), unit: "px" }; } if(real_value == "auto"){ return { amount: 0, unit: "px" }; } if(given_value.indexOf("%") != -1){ var fraction = given_value.substring(0, given_value.length - 1) / 100; return { amount: (real_value.substring(0, real_value.length - 2) * fraction), unit: "px" }; } if(!given_value){ return { amount: real_value.substring(0, real_value.length - 2), unit: "px" }; } }, /* * Start the animation */ start: function(){ var self = this; var start_time = new Date().getTime(); var freq = (1 / this.options.duration); var interval = setInterval(function(){ var elapsed_time = new Date().getTime() - start_time; if(elapsed_time &lt; self.options.duration){ var f = elapsed_time * freq; for(var i in self.rules){ for(var j in self.rules[i].changes){ self.step(self.rules[i].element, self.rules[i].changes[j], f); } } } else{ clearInterval(interval); for(var i in self.rules){ for(var j in self.rules[i].changes) self.step(self.rules[i].element, self.rules[i].changes[j], 1); } } }, 10); }, /* * Perform an animation step * Only works with position-based animations */ step: function(element, change, fraction){ var new_value; switch(change.style){ case 'height': case 'width': case 'top': case 'bottom': case 'left': case 'right': case 'marginTop': case 'marginBottom': case 'marginLeft': case 'marginRight': new_value = Math.round(change.from.amount - (fraction * (change.from.amount - change.to.amount))) + change.to.unit; break; } if(new_value) element.css(change.style, new_value); } }); </code></pre> <p>Then the original Accordion class only needs to be modified in the animate method to make use of the new call.</p> <pre><code>Accordion = function(container_id, options){ this.init(container_id, options); } $.extend(Accordion.prototype, { container_id: '', options: {}, active_tab: 0, animating: false, button_position: 'below', duration: 250, height: 100, handle_class: ".handle", section_class: ".section", init: function(container_id, options){ var self = this; this.container_id = container_id; this.button_position = this.get_button_position(); // The height of each section, use the height specified in the stylesheet if possible this.height = $(this.container_id + " " + this.section_class).css("height"); if(options &amp;&amp; options.duration) this.duration = options.duration; if(options &amp;&amp; options.active_tab) this.active_tab = options.active_tab; // Set the first section to have a height and be "open" // All the rest of the sections should have 0px height $(this.container_id).children(this.section_class).eq(this.active_tab) .addClass("open") .css("height", this.height) .siblings(this.section_class) .css("height", "0px"); // figure out the state of the handles this.do_handle_logic($(this.container_id).children(this.handle_class).eq(this.active_tab)); // Set up an event handler to animate each section $(this.container_id + " " + this.handle_class).mouseover(function(){ if(self.animating) return; self.animate($(this)); }); }, /* * Determines whether handles are above or below their associated section */ get_button_position: function(){ return ($(this.container_id).children(":first").hasClass(this.handle_class) ? 'above' : 'below'); }, /* * Animate the accordion from one node to another */ animate: function(handle){ var active_section = (this.button_position == 'below' ? handle.prev() : handle.next()); var open_section = handle.siblings().andSelf().filter(".open"); if(active_section.hasClass("open")) return; this.animating = true; // figure out the state of the handles this.do_handle_logic(handle); // Close the open section var arr = new Array(); arr.push({ element: open_section, styles: { "height": "0px" } }); arr.push({ element: active_section, styles: { "height": this.height } }); new ParallelAnimations(arr, {duration: this.duration}); var self = this; window.setTimeout(function(){ open_section.removeClass("open"); active_section.addClass("open"); self.animating = false; }, this.duration); }, /* * Update the current class or "state" of each handle */ do_handle_logic: function(handle){ var all_handles = handle.siblings(".handle").andSelf(); var above_handles = handle.prevAll(this.handle_class); var below_handles = handle.nextAll(this.handle_class); // Remove all obsolete handles all_handles .removeClass("handle_on_above") .removeClass("handle_on_below") .removeClass("handle_off_below") .removeClass("handle_off_above"); // Apply the "on" state to the current handle if(this.button_position == 'below'){ handle .addClass("handle_on_below"); } else{ handle .addClass("handle_on_above"); } // Apply the off above/below state to the rest of the handles above_handles .addClass("handle_off_above"); below_handles .addClass("handle_off_below"); } }); </code></pre> <p>The HTML is still called the same way:</p> <pre><code>&lt;html&gt; &lt;head&gt; &lt;title&gt;Parallel Accordion Animation&lt;/title&gt; &lt;script type="text/javascript" src="jquery.js"&gt;&lt;/script&gt; &lt;script type="text/javascript" src="ui.js"&gt;&lt;/script&gt; &lt;script type="text/javascript"&gt; $(document).ready(function(){ new Accordion("#accordion"); }); &lt;/script&gt; &lt;style type="text/css"&gt; #accordion{ position: relative; } #accordion .handle{ width: 260px; height: 30px; background-color: orange; } #accordion .section{ width: 260px; height: 445px; background-color: #a9a9a9; overflow: hidden; position: relative; } &lt;/style&gt; &lt;/head&gt; &lt;body&gt; &lt;div id="accordion"&gt; &lt;div class="section"&gt;&lt;!-- --&gt;&lt;/div&gt; &lt;div class="handle"&gt;handle 1&lt;/div&gt; &lt;div class="section"&gt;&lt;!-- --&gt;&lt;/div&gt; &lt;div class="handle"&gt;handle 2&lt;/div&gt; &lt;div class="section"&gt;&lt;!-- --&gt;&lt;/div&gt; &lt;div class="handle"&gt;handle 3&lt;/div&gt; &lt;div class="section"&gt;&lt;!-- --&gt;&lt;/div&gt; &lt;div class="handle"&gt;handle 4&lt;/div&gt; &lt;div class="section"&gt;&lt;!-- --&gt;&lt;/div&gt; &lt;div class="handle"&gt;handle 5&lt;/div&gt; &lt;/div&gt; &lt;/body&gt; &lt;/html&gt; </code></pre> <p>There are a few things I may add in the future: - Queued Animations - Animations for other types of styles (colors,etc)</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload