I am writing something similar to the JQuery UI accordion, but vertical. I have it working pretty well with one exception. When you click the third tab, it floats left and shows the required text as expected, but it moves to a position before the second tab. Making the tab order 132 rather than 123. In every other state the numbers are ok.
Any thoughts on making the float stop in the correct order
I am aware of other vertical accordions that could be used but js is one of my weaker areas, I'm doing this more for learning.
I have it saved on a jsfiddle
My Javascript Code
$(document).ready(function(){
$("#1").css("background-color","#191970");
$("#1").css("width", "50px");
$("#1").css("float", "left");
$("#2").css("background-color","#191970");
$("#2").css("width", "50px");
$("#2").css("float", "right");
$("#3").css("background-color","#191970");
$("#3").css("width", "50px");
$("#3").css("float", "right");
$("#boxmain").css("background-color", "#CCC");
$("#boxmain").css("width", "400px");
$("#boxmain").text($("#onet").text());
$('p').hide();
$("#1").click(function() {
$("#2").css("float", "right");
$("#3").css("float", "right");
$("#boxmain").effect("highlight", {color: '#DDD'}, 900);
$("#boxmain").text($("#onet").text());
});
$("#2").click(function() {
$("#2").css("float", "left");
$("#3").css("float", "right");
$("#boxmain").effect("highlight", {color: '#DDD'}, 900);
$("#boxmain").text($("#twot").text());
});
$("#3").click(function() {
$("#3").css("float", "left");
$("#2").css("float", "left");
$("#boxmain").effect("highlight", {color: '#DDD'}, 900);
$("#boxmain").text($("#threet").text());
});
});
I can help you simplify this quite a lot. There's a lot to read, but you can see it working at jsfiddle first if you like. You don't need to swap about the floats, you can just swap about the different containers.
First, some CSS:
.accordion {
height:200px;
float: left;
border:#fff solid 1px;
border-radius: 10px 10px 10px 10px;
color:white;
width: 50px;
background: #191970;
}
.boxMain {
width: 400px;
background: #CCC;
}
Then HTML- notice how I use the accordion class to tidy it up:
<div style="height:200px;width:558px;" id="box">
<div id="1" class="accordion">1</div>
<div id="boxmain" class="accordion boxMain"></div>
<div id="2" class="accordion">2</div>
<div id="3" class="accordion">3</div>
</div>
<p id="onet">Number One Text</p>
<p id="twot">Number Two Text</p>
<p id="threet">Number Three Text</p>
Now the script. I have removed all the CSS statements because it's done with CSS instead. I'll explain the .click() method afterwards.
$(document).ready(function(){
$("#boxmain").text($("#onet").text());
$('p').hide();
$("#1").click(function() {
$("#boxmain").insertAfter(this);
$("#boxmain").effect("highlight", {color: '#DDD'}, 900);
$("#boxmain").text($("#onet").text());
});
$("#2").click(function() {
$("#boxmain").insertAfter(this);
$("#boxmain").effect("highlight", {color: '#DDD'}, 900);
$("#boxmain").text($("#twot").text());
});
$("#3").click(function() {
$("#boxmain").insertAfter(this);
$("#boxmain").effect("highlight", {color: '#DDD'}, 900);
$("#boxmain").text($("#threet").text());
});
});
The click method uses the concept of "this" to refer to the element that click() is running on. In the case of $("#1").click() $(this) refers to #1. Instead of trying to shuffle floats around, you move the #boxmain element around instead.
Your divs are ordered that way in the markup. You won't be able to get the effect you're going for by changing float directions. Instead you can move your boxmain div around. Consider this code instead :
http://jsfiddle.net/Lanny/4snqy/18/
Related
I am very new to JS/JQuery/JQueryUI but have made a few things work on a new site I'm working on.
I've set up a basic navbar where a .click makes different divs slide into view with .show while the other three pop out of existence with .hide. I was extremely proud of myself even though this is super basic.
My issue is that one of these divs contains a YouTube iframe. To get it to stop playing when another div is shown, I just remove the src with .attr (clunky, I know). This means that since the source is re-appended to the iframe each time, going back to that div is slower than I want it to be, and jQuery stutters.
I've put a stripped down version into a JSFiddle. Any suggestions on improving the performance would be greatly appreciated!
PS: The video I have as a placeholder is hilarious and you should enjoy it! :)
HTML:
<div class="button" id="home">1</div>
<div class="button" id="about">2</div>
<div class="button" id="latest">3</div>
<div class="button" id="contact">4</div>
<div class="home"><iframe class="video" id="homeVid"
src="https://www.youtube.com/embed/gspaoaecNAg?controls=0?showinfo=0?rel=0?enablejsapi=1"
frameborder="0" allowfullscreen></iframe></div>
<div class="content about"></div>
<div class="content latest"></div>
<div class="content contact"></div>
CSS
.content {
width: 600px;
height: 480px;
display: none;
clear:both
}
.home, .video {
width: 600px;
height: 480px;
display: flex;
clear:both;
background-color: #CCC
}
.about {background-color: #F00}
.latest {background-color: #0F0}
.contact {background-color: #00F}
.button {
width: 25px;
height: 25px;
border: 1px solid black
}
JavaScript
$(document).ready(function() {
var urlhome = $('#homeVid').attr('src');
$('#home').click(function() {
$('.home').show('slide', {direction: 'right', easing: 'swing'}, 400);
$('.about, .contact, .latest').hide(0);
$('#homeVid').attr('src', urlhome);
});
$('#about').click(function() {
$('.about').show('slide', {direction: 'right', easing: 'swing'}, 400);
$('.home, .contact, .latest').hide(0);
$('#homeVid').attr('src', ' ');
});
$('#latest').click(function() {
$('.latest').show('slide', {direction: 'right', easing: 'swing'}, 400);
$('.home, .contact, .about').hide(0);
$('#homeVid').attr('src', ' ');
});
$('#contact').click(function() {
$('.contact').show('slide', {direction: 'right', easing: 'swing'}, 400);
$('.home, .about, .latest').hide(0);
$('#homeVid').attr('src', ' ');
});
});
Indeed, adding and removing the iframe is costly in terms of performance. Instead we must stop the playback and hide it.
This necessitates to insert it differently into the document, using the YouTube Player API Reference for iframe Embeds. Then we do this:
HTML
<div class="content home">
<div id="player"></div>
</div>
var player;
JavaScript
$(window).load(function(){
player = new YT.Player('player', {
height: '480',
width: '600',
videoId: 'gspaoaecNAg',
});
});
We can simply use player.stopVideo(); whenever we hide the home element. But if only it was so simple.
Using jQuery's hide() has side effects, because the way it hides elements is by setting their CSS to display:none which effectively removes them from the document. This destroys the iframe and recreates it on show(), which presents the same performance issue as before.
We need something more subtle, hiding the elements by putting them aside. For this we use positionning:
.hidden {
position:fixed;
left:200%;
}
This puts them further on the right of the document, outside the viewport and since the units are relative, it can never be vsible no matter how much we stretch the window. This necessitates a few changes in HTML, plus some others for an optimization I will detail further below.
HTML:
<div class="button" id="home">1</div>
<div class="button" id="about">2</div>
<div class="button" id="latest">3</div>
<div class="button" id="contact">4</div>
<div class="content home">
<div id="player"></div>
</div>
<div class="content about hidden"></div>
<div class="content latest hidden"></div>
<div class="content contact hidden"></div>
We have added the class hidden to all elements not visible at the start. We also added a class describing the elements themselves and set to the id of their corresponding button. And we have the content class in each element.
JavaScript:
var player;
$(window).load(function(){
player = new YT.Player('player', {
height: '480',
width: '600',
videoId: 'gspaoaecNAg',
});
});
$(document).ready(function() {
var all = $('.content');
$('.button').click(function() {
all.addClass('hidden');
player.stopVideo();
$('.'+this.id).animate({
'left': '0px',
easing: 'swing'
}, 400, function(){
$(this).removeClass('hidden')
.removeAttr('style');
});
});
});
This has been optimized to avoid checking each element individually. The first part has been explained before, here is how the rest goes:
var all = $('.content');
This selects all the .content elements and keeps them referenced outside the callback in the variable all, so we only have to do this once when the document loads.
We create the callback on all button elements. The next step assumes a click event has been received.
We set all .content elements to hidden. Effectively this should only affect the one currently not hidden.
We stop the video. This will only affect the embedded iframe and we don't bother checking which .content element is active because stopping an already stopped video does nothing special.
Using the id of the button that triggered the click event, we select the corresponding .content element.
We replace show() with animate() and use it to modify the CSS property that is used in the class hidden. This will slide the element from its hidden position to it's normal position.
The animation has a callback executed when it's done. We use it to first remove the hidden class from our now visible element, then to remove the style attribute in which our animation has set left:0px;, as leaving this there would interfere later.
And we're done. This should now be smooth. A demo is available on this JSFiddle.
There is a plethora of similar questions around but none of them seem to be looking for what I'm looking for, or else none of the answers are useful for my purposes.
The jsfiddle: http://jsfiddle.net/tumblingpenguin/9yGCf/4/
The user will select an option and the page will reload with their option applied. What I need is for the "option list" DIV to be scrolled down to the selected option such that it is in the center of the option list.
The HTML...
<div id="container">
<a href="#">
<div class="option">
Option 1
</div>
</a>
<!-- other options -->
<a href="#">
<div class="option selected"> <!-- scroll to here -->
Option 4
</div>
<!-- other options -->
<a href="#">
<div class="option">
Option 7
</div>
</a>
</div>
The selected option is marked with the selected class. I need to somehow scroll the DIV down to the selected option.
The CSS...
#container {
background-color: #F00;
height: 100px;
overflow-x: hidden;
overflow-y: scroll;
width: 200px;
}
a {
color: #FFF;
text-decoration: none;
}
.option {
background-color: #c0c0c0;
padding: 5px;
width: 200px;
}
.option:hover {
background-color: #ccc;
}
.selected {
background-color: #3c6;
}
I've seen this done on other websites so I know it's possible—I just haven't a clue where to begin with it.
P.S. jQuery solutions are acceptable.
Something like this http://jsfiddle.net/X2eTL/1/:
// On document ready
$(function(){
// Find selected div
var selected = $('#container .selected');
// Scroll container to offset of the selected div
selected.parent().parent().scrollTop(selected[0].offsetTop);
});
Without the jQuery (put this at the bottom of the < body > tag:
// Find selected div
var selected = document.querySelector('#container .selected');
// Scroll container to offset of the selected div
selected.parentNode.parentNode.scrollTop = selected.offsetTop;
demo: http://jsfiddle.net/66tGt/
Since you said JQuery answers are acceptable, here's an example of what you're looking for:
$('body, html').animate({ scrollTop: div.offset().top-210 }, 1000);
Replace div for whatever element you want to scroll to.
Here is one possible solution that may work for you:
Demo Fiddle
JS:
$('#container').scrollTop( $('.selected').position().top );
Take a look at this fiddle : http://jsfiddle.net/9yGCf/8/
As requested it scrolls to the middle of the div (you can change the offset by however much you want to make little adjustments). I would probably suggest setting either a line height with some padding and whatnot and then do the math to change the offset that I have at -40 so that it does put it in the middle.
But I used jquery and came up with this quick little code... also added some code to change the selected option
$('.option').click(function(){
$('.selected').removeClass('selected');
$(this).addClass('selected');
$(this).parent().parent().scrollTop(selected[0].offsetTop - 40);
});
This magical API will automatically scroll to the right position.
element.scrollIntoView({ block: 'center' })
See more details:
https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
I am writing a script that will animate a set of jQuery Elements, but I'm running into some issues. Here are my requirements:
Sequential animations
Callback functionality after all animations are complete. Callback can be defined globally
Animation works on floated elements with
Entire solution can be js/jquery/css or a combination
Here's what I've gotten so far: http://jsfiddle.net/fmpeyton/cqAws/
HTML
<div class="block">Im a box</div>
<div class="block">me too</div>
<div class="block">and me!</div>
<div class="block">am I?</div>
<div class="block">yes.</div>
<div class="block">Im a box</div>
<div class="block">me too</div>
<div class="block">and me!</div>
<div class="block">am I?</div>
<div class="block">yes.</div>
<div class="block">Im a box</div>
<div class="block">me too</div>
<div class="block">and me!</div>
<div class="block">am I?</div>
<div class="block">yes.</div>
CSS
.block{
float:left;
width:100px;
background: red;
margin: 0 10px;
padding: 10px;
}
.hiddenForAnimation{ opacity:0; margin-top:-20px; }
JS
$(function(){
$('.block').addClass('hiddenForAnimation').each(function(i){
var delay = i * 200,
animationSpeed = 800;
$(this).delay(delay).animate({opacity: '1', marginTop: '0px'
}, animationSpeed, function(){ if(typeof afterPageAnimation === 'function' && i === $(this).length){ setTimeout(afterPageAnimation, delay + animationSpeed);} $(this).removeClass('hiddenForAnimation').attr('style',''); });
});
});
function afterPageAnimation(){ alert('animation is done!'); }
My issues:
Is there a better way to refactor this JS script to be sequential? Using delay() is effective, but not elegant.
The callback is not being executed directly after the animations
When the last element in a row finishes animating, the first element in the next row starts at the far right, then jumps to the left (I suspect margin-top has something to do with this.)
Thanks!
This works
http://jsfiddle.net/cqAws/12/
Remember: In positioning animations, use position:relative or position:absolute and play with top, left, right, bottom instead of margins.
It's better
EDIT: made it a little better.
new
$(function(){
j=0;
$('.block').each(function(i){
var interv = +(i*800);
var animationSpeed = 800;
$(this).toggleClass('hiddenForAnimation')
.delay(interv)
.animate({opacity: '1', marginTop: '0'},animationSpeed,function(){
j++;
$(this).delay(+(interv+animationSpeed))
.toggleClass('hiddenForAnimation')
.attr('style','');
if(j>=+($('.block').length)) afterPageAnimation();
});
});
});
function afterPageAnimation(){ alert('cool'); }
FIDDLE
For future viewers:
I've solved this by creating a small Jquery plugin found here: https://github.com/fillswitch/Jquery-Sequential-Animations
Hope this helps some other users in the future!
So I almost have my code working how I want, but can't get my animation synched together just right. I am trying to animate a cursor highlighting text, and then clicking on a button. The problem is that the cursor is either too slow or too fast. I am trying to make this dynamic so that no matter how long the text is I can still have the animation synch. I know that it is probably just a math issue, but can't quite get my head around it. Something about trying to match pixels with milliseconds is making my head spin. Please help before I pull out all my hair. Thanks.
Here is the html
<p><span id="container">I need to be highlighted one character at a time</span>
<input id="click" type="button" value="click me"/></p>
<img src="http://dl.dropbox.com/u/59918876/cursor.png" width="16"/>
Here is the CSS
#container{
font-size: 16px;
margin-right: 10px;
}
.highlight{
background: yellow;
}
img{
position: relative;
top: -10px;
}
And the javascript
function highlight(){
var text = $('#container').text(); //get text of container
$('#click').css('border','none'); //remove the border
$('img').css('left', '0px'); //reset the cursor left
$('img').animate({left: $('#container').width() + 40}, text.length*70); //animation of cursor
$('#container').html('<span class="highlight">'+text.substring(0,1)+'</span><span>'+text.substring(1)+'</span>'); //set the first html
(function myLoop (i) {//animation loop
setTimeout(function () {
var highlight = $('.highlight').text();
var highlightAdd = $('.highlight').next().text().substring(0,1);;
var plain = $('.highlight').next().text().substring(1);
$('#container').html('<span class="highlight">'+highlight+highlightAdd+'</span><span>'+plain+'</span>');
if (--i) myLoop(i);// decrement i and call myLoop again if i > 0
}, 70)
})(text.length);
setTimeout(function () {
$('#click').css('border','1px solid black');
}, text.length*85);
}
highlight();
var intervalID = setInterval(highlight, $('#container').text().length*110);
//clearInterval(intervalID);
Here is a link to the fiddle I have been playing around in.
This will probably get me down voted but maybe you will get some better idea...
Fiddle Here
$(document).ready(function() {
$('p').click(function(){
$('span').animate({'width':'100'},1000);
$('.cursor').animate({marginLeft: 100},1000);
});
});
Thanks to Dejo, I was able to modify my code to make this work exactly as I wanted. It was much easier to increase the width of one span rather than trying to expand one span while shrinking another. This also allowed me to have both the cursor moving and the span width increasing animations run in sync.
The HTML
<p><span id="highlight"></span><span id="container">I need to be highlighted one character at a time</span><input id="click" type="button" value="click me"/></p>
<img id="cursor" src="http://dl.dropbox.com/u/59918876/cursor.png" width="16"/>
The CSS
p{
position: relative;
font-size: 16px;
}
#highlight{
position: absolute;
background-color:yellow;
height:20px;
z-index:-50;
}
#cursor{
position: relative;
top: -10px;
}
#click{
margin-left; 10px;
}
And the javascript
function highlight(){
var textLength = $('#container').text().length;
$('#click').css('border','none'); //remove the border
$('#cursor').css('left', '0px'); //reset the cursor left
$('#highlight').width(0);
$('#highlight').animate({width: $('#container').width()}, textLength * 70);
$('#cursor').animate({left: '+='+$('#container').width()} , textLength * 70, function(){
$('#cursor').animate({left: '+=30'} , textLength * 20);
});
setTimeout(function () {
$('#click').css('border','1px solid black');
}, textLength*100);
}
highlight();
var intervalID = setInterval(highlight, $('#container').text().length*120);
//clearInterval(intervalID);
I realize it's quite a bit late, but here's a bit of help (for future reference).
The JQuery animate function is, by default, set an easing of swing, which means that the speed of the animation will vary throughout (see here).
To (kind of) fix the problem, I added the linear option to the animate method for the cursor, and increased its speed slightly.
You can see this new version at JSFiddle.
However, since the setTimeout loop can be slowed for some reasons, the animation may not be in sync.
I have some code, that simulate google images effect.
How can I animate nested divs in div class="productBox", not only this div???
I want to change height of "imageProduct" class during animation also.
Here this code on jsFiddle: http://jsfiddle.net/S2svG/57/
Here is html:
<div class="productBox">
<div class="productImage"><img src="http://some_image.jpg"></div>
<div class="productTitle">Product title</div>
<div class="productDescription">Here is description of the product.</div>
<div class="buyButton">Buy this!</div>
</div>
And js:
$(function(){
$.fn.popOut=function(user_opts){
return this.each(function(){
var opts=$.extend({
useId:"poppedOut",
padding:20,
border:0,
speed:200
},user_opts);
$(this).mouseover(function(){
// kill any instance of this already
$("#"+opts.useId).remove();
// make a copy of the hovered guy
var $div=$(this).clone();
// setup for prelim stuff
$div.css({
"position":"absolute",
"border":opts.border,
"top":$(this).offset().top,
"left":$(this).offset().left,
"-moz-box-shadow":"0px 0px 12px black",
"-webkit-box-shadow":"0px 0px 12px black",
"z-index":"99"
});
// store all of the old props so it can be animate back
$div.attr("id",opts.useId)
.attr("oldWidth",$(this).width())
.attr("oldHeight",$(this).height())
.attr("oldTop",$(this).offset().top)
.attr("oldLeft",$(this).offset().left)
.attr("oldPadding",$(this).css("padding"));
// put this guy on the page
$("body").prepend($div);
// animate the div outward
$div.animate({
"top":$(this).offset().top-Math.abs($(this).height()-opts.height),
"left":$(this).offset().left-opts.padding,
"height":opts.height,
"padding":opts.padding
},opts.speed);
// loop through each selector and animate it to its css object
for(var eachSelector in opts.selectors){
var selectorObject=opts.selectors[eachSelector];
for(var jquerySelector in selectorObject){
var cssObject=selectorObject[jquerySelector];
$div.find(jquerySelector).animate(cssObject,opts.speed);
}
}
$div.mouseleave(function(){
$("#"+opts.useId).animate({
width:$(this).attr("oldWidth"),
height:$(this).attr("oldHeight"),
top:$(this).attr("oldTop"),
left:$(this).attr("oldLeft"),
padding:$(this).attr("oldPadding")
},0,function(){
$(this).remove();
});
});
});
});
};
$(".productBox").popOut({
height:300,
border:"1px solid #333"
});
});
Thanks in advance!!!
$(this).find(".productImage").animate({...});