how to do parallel animation on same element - javascript

Here is code in jsfiddle !
Here is the actual site !
Problem 1: It seem's that when I call functions when clicking enter they don't execute on after each other , it sometimes works if it goe's in parallel and does everything at once! But this isn't the actual problem, it's something I would love some advice!
Problem Actual: When I call enter I switch all the clases and then do a parallel animation on div.third(making background green or red and then fading out), problem is, when I do fast enough it doesn't resize div.fourth untill background animation finished. So I thought solution for this would be a parallel animation witch doesn't interact with main animation thus switchClases().
Code where all the magic happens:
// Do everytime we press a key
$(document).keydown(function(){
// By presing 'Enter' we call exec.
$("#wraper input.third").bind('keydown',function(e){
// Make key variable by phrasing the event
var keyPresed = (e.keyCode ? e.keyCode : e.which);
// Allow only backspace, delete and enter
if (keyPresed == 46 || keyPresed == 8 || keyPresed == 13){
// If this is true animation is still in progress
if (transAct) {
// OBLIVION
}
// Or else start another animation and execution
else{
// If 'enter' is pressed then and new row and execute everything
if((keyPresed == 13) && $("input.third").val()){
//Set the new uniqueId
uniqueId++;
$("div.second").addClass("class"+uniqueId);
//Get result number because it will not be his name anymore
result = $("input.third").val();
//Switch clases
SwitchClases(_this);
transAct = true;
// Her we actualy insert the new line
$("<div class='first'>9 x 8 = <input class='first' type='text' disabled='true' maxlength='2'/></div>").css("opacity", "0").hide().prependTo(_this).slideDown().animate({opacity: 0.1},function(){
transAct = false;
})
$("div.third").append(" "+result) // Write down inputed result
$("input.third").fadeOut().remove() // Drop input box into black hole
$("div.fifth").fadeOut().remove(); // Do same thing to last division
// Check if answer was correct!
// Here are two examples with whom you can play as much as you like
//$(".leftSide div.class"+(uniqueId-1)).stop().animate({backgroundColor: '#00DD00'},100).animate({backgroundColor: 'white'},900);
// $(".leftSide").stop().animate({backgroundColor: '#DD0000'},100).animate({backgroundColor: 'white'},900);
//Now set focus to next input area , so we can continue and be lazy by not clicking on new input box!
$('.newEleCont input.second').focus();
}
}
}
// Restrict inputing any other character besides a number
else {
// Ensure that it is a number and stop the keypress
if ((keyPresed < 48 || keyPresed > 57) && (keyPresed < 96 || keyPresed > 105 )) {
e.preventDefault();
}
}
});
});
1) How could I find solution for double animation?
2) How could I improve this code?(that is , using less jquery)
EDIT: As you can see I added additional uniqueID class to every new div.third. And what I want to do is to cast backgroundColor animation only on given uniqueID BUT not interacing with basic third>fourth>fifth class animations, like if they did there own separate things!

Parallel Animation in jQuery : You can do parallel animation by passing the properties object to animate function. For example:
var animateProperties = {
top:50px,
left:100px,
width:300px,
}
object.animate(animateProperties);
and you can use stop function to stop the animation in progress. I have modified your code, the code that calls animate function is given below.
var style = {
"opacity": opacity,
"font-size": fontSize + "px"
}
if(animate){
if(index == config.activeIndex + 1){
style.backgroundColor = '#00EE00';
$(row).stop(true, true).animate(style, 100)
.animate({backgroundColor: 'white'}, 1200);
}else{
$(row).stop(true, true).animate(style, 100);
}
}else{
$(row).css(style);
}
You can find the final version of code here http://jsfiddle.net/diode/rBqVE/6/
I have made this configurable using a config object. You can find it in the code, but to get the best result you will have to modify css also.

See the function dequeue
http://api.jquery.com/jQuery.dequeue/
jQuery adds each animate call to a queue. Using dequeue you can invoke next animate call in the queue.
Here dequeue demo you can see a simple demonstration.
Also see jQuery effect http://jqueryui.com/demos/effect/. Its not for this purpose, but might be useful.

Related

How to detect a double-click-drag in Javascript/jQuery

I'd like to detect in a web page when the user selects some text by dragging. However, there's one scenario in Windows which I'm calling a "double-click-drag" (sorry if there's already a better name I don't know) and I can't figure out how to detect it. It goes like this:
press mouse button
quickly release mouse button
quickly press mouse button again
drag with the button held down
This causes the dragging to select whole Words. It's quite a useful technique from the user perspective.
What I'm trying to do is tell the difference between a double-click-drag and a click followed by a separate drag. So when I get to step 2 I will get a click event but I don't want to treat it as a click yet; I want to see if they're about to immediately do step 3.
Presumably Windows detects this on the basis of the timing and how much the mouse has moved between step 2 and 3, but I don't know the parameters it uses so I can't replicate the windows logic. note that even if the mouse doesn't move at all between step 2 and 3, I still get a mousemove event.
I realise that I should be designing interfaces that are touch-friendly and device-neutral, and I have every intention of supporting other devices, but this is an enterprise application aimed at users on windows PCs so I want to optimize this case if I can.
We've done something similar. Our final solution was to create a click handler that suppressed the default response, and then set a global variable to the current date/time. We then set another function to fire in some 200ms or so that would handle the "click" event. That was our base function.
We then modified it to look at the global variable to determine when the last click occured. If it's been less than 200ms (modify based on your needs) we set a flag that would cause the click handler to fizzle and called a double click handler.
You could extend that approach by having your click and double click handlers manually fire the drag functionality.
I don't have access to the aforementioned code right now, but here is an example of that framework being used to track keyboard clicks to determine if a scanner or user has finished typing in a field:
var lastKeyPress = loadTime.getTime();
// This function fires on each keypress while the cursor is in the field. It checks the field value for preceding and trailing asterisks, which
// denote use of a scanner. If these are found it cleans the input and clicks the add button. This function also watches for rapid entry of keyup events, which
// also would denote a scanner, possibly one that does not use asterisks as control characters.
function checkForScanKeypress() {
var iVal = document.getElementById('field_id').value;
var currentTime = new Date()
var temp = currentTime.getTime();
if (temp - lastKeyPress < 80) {
scanCountCheck = scanCountCheck + 1;
} else {
scanCountCheck = 0;
}
lastKeyPress = currentTime.getTime();
}
// The script above tracks how many successive times two keyup events have occurred within 80 milliseconds of one another. The count is reset
// if any keypress occurs more than 80 milliseconds after the last (preventing false positives from manual entry). The script below runs
// every 200 milliseconds and looks to see if more than 3 keystrokes have occurred in such rapid succession. If so, it is assumed that a scanner
// was used for this entry. It then waits until at least 200 milliseconds after the last event and then triggers the next function.
// The 200ms buffer after the last keyup event insures the function is not called before the scanner completes part number entry.
function checkForScan() {
var currentTime = new Date();
var temp = currentTime.getTime();
if (temp - lastKeyPress > 200 && scanCountCheck > 3) {
FiredWhenUserStopsTyping();
scanCountCheck = 0;
}
setTimeout(checkForScan, 200);
}
Here is some code that I just wrote up based upon the above ideas. It's not tested and doesn't contain the actual drag events, but should give you a good starting point:
var lastClick = loadTime.getTime();
function fireOnClickEvent(event) {
event.preventDefault;
var currentTime = new Date()
var temp = currentTime.getTime();
if (temp - lastClick < 80) {
clearTimeout(tf);
doubleClickHandler();
} else {
tf = setTimeout(singleClickHandler, 100);
}
lastClick = currentTime.getTime();
}
function singleClickHandler() {
// Begin normal drag function
}
function doubleClickHandler() {
// Begin alternate drag function
}
A single double-click-drag action involves the following events in sequence:
mousedown -> mouseup -> click -> mousedown -> mousemove
With that in mind, I came up with this simple solution:
let maybeDoubleClickDragging = false;
let maybeDoubleClickDraggingTimeout;
const element = document.querySelector('#container');
element.addEventListener("click", function (e) {
maybeDoubleClickDragging = true;
element.removeEventListener("mousemove", handleMousemove);
});
element.addEventListener("mousedown", (e) => {
element.addEventListener("mousemove", handleMousemove);
if (maybeDoubleClickDragging) {
clearTimeout(maybeDoubleClickDraggingTimeout);
return;
}
});
element.addEventListener("mouseup", (event) => {
maybeDoubleClickDraggingTimeout = setTimeout(() => {
maybeDoubleClickDragging = false;
}, 200);
});
function handleMousemove(e) {
if(maybeDoubleClickDragging) {
element.textContent = 'you are double-click-dragging'
}
}
#container {
width: 300px;
height: 300px;
background: yellow;
}
<div id="container"></div>

Moving a box in JavaScript again -- the program seems to be detecting two key presses even though I'm only pressing one

I'm trying to build on the top answer here by adding "gravity" such that the box always moves down unless a key is pressed.
I've been fiddling for a couple of hours now and I can't figure it out. In the previous code he send two variables to the calculateNewValue function, for top and left of the css position.
I thought I would simply be able to break these two tests for true/false key presses out into four, and then add a +1 for when the up arrow is false, hence the box will always fall down unless you tell it not to.
It almost works, but the box moves down and to the right, instead of just down. And gravity doesn't work like that.
This must have something to do with top and left being used to move the box in two directions. But if the event handler is storing the keycode for only one key, wouldn't all the other tests return false? How can I get it to not move right?
$(function(){
var pane = $('#pane'),
box = $('#box'),
maxValue = pane.width() - box.width(),
keysPressed = {},
distancePerIteration = 3;
function calculateNewValue(oldValue) {
var newValue = parseInt(oldValue, 10)
- (keysPressed[37] ? distancePerIteration : 0)
- (keysPressed[38] ? distancePerIteration : 0)
+ (keysPressed[39] ? distancePerIteration : 0)
+ (keysPressed[40] ? distancePerIteration : 1)
return newValue < 0 ? 0 : newValue > maxValue ? maxValue : newValue;
}
$(window).keydown(function(event) { keysPressed[event.which] = true; });
$(window).keyup(function(event) { keysPressed[event.which] = false; });
setInterval(function() {
box.css({
left: function(index ,oldValue) {
return calculateNewValue(oldValue);
},
top: function(index, oldValue) {
return calculateNewValue(oldValue);
}
});
}, 20);
});
Usually you only use keyup() function. Then the keypress will only fire one event. Only in special cases it is necessary to use keydown().
Your code is flawed. Every 20 milliseconds you modify the the left/top of the box by the same amount every time.
The way you have set up the code, the left and top values always increase by the same amount every time the CSS is updated - so the box will always move either upleft or downright depending on if you press left/up keys.
If you're just trying to move the box up and down then you probably want to change the code not to modify the left attribute - and then change the calculateNewValue to not use the ascii for left/right arrows.

using a button to switch between two states

Essentially I want to use a button to bring a div to the front using the CSS z-index and then when pressing the button again I want it to revert back to its original state.
This is the code I have got so far and it will happily change it first time round but it wont revert it back.
function thumbnail(){
if (document.getElementById("div").style.zIndex= -3){
document.getElementById("div").style.zIndex= -2;
}
if (document.getElementById("div").style.zIndex= -2){
document.getElementById("div").style.zIndex= -3;
}
}
function thumbnail(){
var depth = document.getElementById("div").style.zIndex;
document.getElementById("div").style.zIndex = (depth == -3)? -2 : -3;
}
This slightly more efficient version avoids traversing the DOM more than once:
function thumbnail () {
var elStyle = document.getElementById ("div").style;
elStyle.zIndex = elStyle.zIndex == -3 ? -2 : -3;
}
Using div as an id may prove to be confusing when you return to this code later, use a name which identifies the function of the div.

how to make a <div> appear in slow motion

I want the javascript code to show a div in slow motion.
function showDiv(divID)
{
if(document.getElementById(divID).style.display=='none')
{
document.getElementById(divID).style.display='block';
}
}
Here div appears, but not in slow motion. Can anyone help ??
Thanks in advance
Dev..
There is no need of jQuery in this atall , its just a basic I am using your function to explain how thats done.
function showDiv(divID)
{
if(document.getElementById(divID).style.display=='none')
{
document.getElementById(divID).style.display='block';
}
}
What your function is doing is basically removing the whole Element from BOX Model ( the toggle of block and none removes the element totally from the BOX Model so it doesnt occupies any space or anything , this but may / may not cause some layout issues );
Now to animate it in slow motion you need a timing function.
a timing function is a simple mathematical function which gives the value of the property ( opacity in your case ) for a given time or depending on other parameters .
Other then that you also need to use properties like opacity in order to fade it (Opacity is a CSS property that defines the transparency of an element and its childrens )
So let us begin with a very basic show / hide using setTimeout Function in JS.
function getValue(t,dir){
if( dir > 0){
return 0.5*t; /* Y = mx + c */
}else{
return 1-(0.5*t);
}
/*
Here the slope of line m = 0.5.
t is the time interval.
*/
}
function animator(divID){
if(!(this instanceof animator)) return new animator(divID); /* Ignore this */
var Node = document.getElementById(divID),
start = new Date.getTime(), // The initiation.
now = 0,
dir = 1,
visible = true;
function step( ){
now = new Date.getTime();
var val = getValue( now - start,dir)
Node.style.opacity = val;
if( dir > 0 && val > 1 || dir < 0 && val < 0 ){
visible = !(visible*1);
// Optionally here u can call the block & none
if( dir < 0 ) { /* Hiding and hidden*/
Node.style.display = 'none'; // So if were repositioning using position:relative; it will support after hide
}
/* Our animation is finished lets end the continous calls */
return;
}
setTimeout(step,100); // Each step is executated in 100seconds
}
this.animate = function(){
Node.style.display = 'block';
dir *= -1;
start = new Date.getTime();
setTimeout(step,100);
}
}
now you can simply call the function
var magician = new animator('divName');
then toggle its animation by
magician.animate();
Now playing with the timing function you can create whatever possibilities you want as in
return t^2 / ( 2 *3.23423 );
or even higher polynomial equations like
return t^3+6t^2-38t+12;
As you can see our function is very very basic but it explains the point of how to make animations using pure js . you can later on use CSS3 module for animation and trigger those classes with javascript :-)
Or perhaps write a cross browser polyfill using CSS3 where available ( it is faster ) , and JS if not :-) hope that helps
Crossbrowser solution (without jQuery) :
HTML :
<div id="toChange" ></div>
CSS :
#toChange
{
background-color:red;
width:200px;
height:200px;
opacity:0;//IE9, Firefox, Chrome, Opera, and Safari
filter:alpha(opacity=0);//IE8 and earlier
}
Javascript :
var elem=document.getElementById("toChange");
var x=0;
function moreVisible()
{
if(x==1)clearInterval(t);
x+=0.05;
elem.style.opacity=x;
elem.style.filter="alpha(opacity="+(x*100)+")";
}
var t=setInterval(moreVisible,25);
Fiddle demonstration : http://jsfiddle.net/JgxW6/1/
So you have a few jQuery answers but I wouldn't recommend jQuery if fading the div is all you want.
Certainly jQuery makes things easier but it is a lot of overhead for a single simple functionality.
Here is someone that did it with pure JS:
Fade in and fade out in pure javascript
And a CSS3 example:
How to trigger CSS3 fade-in effect using Javascript?
You can use jquery $.show('slow') for the same, if you want to do the same without using jquery then you might be required to code something to show the effect yourself, you may have a look at source of jquery's show function http://james.padolsey.com/jquery/#v=1.6.2&fn=show . alternatively , you can also use fadein() for fade in effect in jquery
Yes you can do it using Jquery. Here is my sample example
$('#divID').click(function() {
$('#book').show('slow', function() {
// Animation complete.
});
});
For details clik here
Thanks.

Jquery - Carasol build finished and would like advice on best practice / neatening up my code

I have been building my own carasol over the past few days.
My Jquery is based on tutorials on the web and also from help and advice from SO.
I am not a Jquery guru just an enthusiast and think my code is a little sloppy, hence the post.
here is a link to the working code: http://jsfiddle.net/JHqBA/2/ (updated link)
basically what happens is:
if someone hits the page with a # values in the url it will show the appropriate slide and example would be www.hello.com#two, this would slide to slide two
if someone clicks the numbers it will show the appropriate slide
next and prev also slide through the slides.
The question is, is there anything i could have wrote better as i know there is alot of duplicate code.
I understand its a big ask but it would help me learn a little more (i think my code is a little old school)
if anyone has any questions please feel free to ask and ill answer what it does or is supposed to do.
Sluap
--- Edit ----
I have made only one aniamtion function now which has got rid of alot of duplicate code.
I have yet to look into on function but will do soon.
I would like to know more about the create a new function, outside of the jQuery ready block as i cant get this working or quite understand how i can get it to work sorry
any more tips would be great ill carry on working on this project till i am happy with it.
also is there a better way to write:
if ($slideNumber == 1) {
$('#prev').attr("class", "not_active")
$('#next').attr("class", "active")
}
else if ($slideNumber == divSum) {
$('#next').attr("class", "not_active");
$('#prev').attr("class", "active");
}
else {
$('#prev').attr("class", "active")
$('#next').attr("class", "active")
};
Jquery full:
$(document).ready(function () {
//////////////////////////// INITAL SET UP /////////////////////////////////////////////
//Get size of images, how many there are, then determin the size of the image reel.
var divWidth = $(".window").width();
var divSum = $(".slide").size();
var divReelWidth = divWidth * divSum;
//Adjust the image reel to its new size
$(".image_reel").css({ 'width': divReelWidth });
//set the initial not active state
$('#prev').attr("class", "not_active");
//////////////////////////// SLIDER /////////////////////////////////////////////
//Paging + Slider Function
rotate = function () {
var triggerID = $slideNumber - 1; //Get number of times to slide
var image_reelPosition = triggerID * divWidth; //Determines the distance the image reel needs to slide
//sets the active on the next and prev
if ($slideNumber == 1) {
$('#prev').attr("class", "not_active")
$('#next').attr("class", "active")
}
else if ($slideNumber == divSum) {
$('#next').attr("class", "not_active");
$('#prev').attr("class", "active");
}
else {
$('#prev').attr("class", "active")
$('#next').attr("class", "active")
};
//Slider Animation
$(".image_reel").animate({
left: -image_reelPosition
}, 500);
};
//////////////////////////// SLIDER CALLS /////////////////////////////////////////////
//click on numbers
$(".paging a").click(function () {
$active = $(this); //Activate the clicked paging
$slideNumber = $active.attr("rel");
rotate(); //Trigger rotation immediately
return false; //Prevent browser jump to link anchor
});
//click on next button
$('#next').click(function () {
if (!$(".image_reel").is(':animated')) { //prevent clicking if animating
var left_indent = parseInt($('.image_reel').css('left')) - divWidth;
var slideNumberOn = (left_indent / divWidth);
var slideNumber = ((slideNumberOn * -1) + 1);
$slideNumber = slideNumber;
if ($slideNumber <= divSum) { //do not animate if on last slide
rotate(); //Trigger rotation immediately
};
return false; //Prevent browser jump to link anchor
}
});
//click on prev button
$('#prev').click(function () {
if (!$(".image_reel").is(':animated')) { //prevent clicking if animating
var left_indent = parseInt($('.image_reel').css('left')) - divWidth;
var slideNumberOn = (left_indent / divWidth);
var slideNumber = ((slideNumberOn * -1) - 1);
$slideNumber = slideNumber;
if ($slideNumber >= 1) { //do not animate if on first slide
rotate(); //Trigger rotation immediately
};
}
return false; //Prevent browser jump to link anchor
});
//URL eg:www.hello.com#one
var hash = window.location.hash;
var map = {
one: 1,
two: 2,
three: 3,
four: 4
};
var hashValue = map[hash.substring(1)];
//animate if hashValue is not null
if (hashValue != null) {
$slideNumber = hashValue;
rotate(); //Trigger rotation immediately
return false; //Prevent browser jump to link anchor
};
});
Question and answer has been moved over to https://codereview.stackexchange.com/questions/8634/jquery-carasol-build-finished-and-would-like-advice-on-best-practice-neateni/8635#8635
1) Separation of Concerns
Start by refactorring your code in to more granular functions.
You can read more about SoF at http://en.wikipedia.org/wiki/Separation_of_concerns
Update:
E.g. Instead of having your reel resizing code inline, put it in it's own function, like this:
function setImageReelWidth () {
//Get size of images, how many there are, then determin the size of the image reel.
var divWidth = $(".window").width();
var divSum = $(".slide").size();
var divReelWidth = divWidth * divSum;
//Adjust the image reel to its new size
$(".image_reel").css({ 'width': divReelWidth });
}
This achieves 2 things:
a. First, it groups a block of code that is logically cohesive, removing it from the main code which results in a much cleaner code habitat.
b. It effectively gives a label to the code block via the function name that is descriptive of what it does, and therefore makes understanding of the code much simpler.
Later, you can also encapsulate the whole thing in it's own "class" (function) and you can move it into it's own js file.
2) The jQuery "on" function
Use the "on" function to attach your click events, rather than the "click" function.
http://api.jquery.com/on/
This has the added advantage of also binding it to future elements matching your selector, even though they do not exist yet.
3) The ready function
// I like the more succinct:
$(handler)
// Instead of:
$(document).ready(handler)
But you might like the more obvious syntax.
Those are just a few things to start with.
-- Update 1 --
Ok, StackOverflow is not really suited to a refactoring work in progress, but we'll make do. I think you should keep your original code block in your question, so that future readers can see where it started and how it systematically improved.
I would like to know more about the create a new function, outside of
the jQuery ready block as i cant get this working or quite understand
how i can get it to work sorry
I am not familiar with jsfiddle.net, but it looks cool and helpful, but might also be a bit confusing if you don't know what is going on. I am not sure I do :), but I think that script editor window results in a .js file that is automatically referenced by the html file.
So here is an example of a function defined outside of the ready block, but referenced from within.
function testFunction () {
alert ('it works');
}
$(document).ready(function () {
testFunction();
// ... other code
});
This should pop up an alert box that says, "it works" when the page is loaded.
You can try it for yourself.
Then, once you got that working, you can refactor other logically cohesive blocks of code into their own functions. Later you can wrap them all up into their own javascript 'class'. But we'll get to that.

Categories