I have an animation linked to scroll position. Whenever the the user scrolls up or down, an animation is triggered for that position to move an element within the view window. If the user scrolls farther, these animations need to queue so that the element moves smoothly along the path.
var target = getAnimation();
var props = {
left: [target.x, target.easing],
top: target.y
};
$("#ball").animate(props, 400, "easeInOutQuad");
The problem with this is that when multiple animations get queued, the ball slows and speeds up in a bad way. What I'd like to do is something like this:
var target = getAnimation();
var props = {
left: [target.x, target.easing],
top: target.y
};
var ball = $("#ball"), queue = ball.queue();
if(ball.queue().length) {
for(var i = 1, len = queue.length; i < len; i++) {
//modify all the other queued animations to use linear easing
}
ball.animate(props, 400, "easeOutQuad");
}
else {
ball.animate(props, 400, "easeInQuad");
}
By starting with an easeIn function, using linear in the middle, and easeOut at the end, I get a much smoother animation. Is there anyway I can access and modify the animations in the queue?
Edit:
Here is a fiddle to demonstrate what I'm trying to achieve: https://jsfiddle.net/reesewill/mtepvguw/
In the fiddle, I am using linear easing, but I'd really like the general affect to be more like easeInOutQuad. However, because I allow queueing, I can't just apply that easing function without it messing up the whole effect (change the linear to easeInOutQuad and click queue a few times quickly to see). Thus, I need something like the above to create the general impression of easeInOutQuad.
Note
, $(selector).queue() returns a reference to the animation queue, an Array. This reference can be modified with standard array methods. See also .dequeue() .
Try utilizing
Array.prototype.splice()
Summary
The splice() method changes the content of an array by
removing existing elements and/or adding new elements.
Syntax
array.splice(start, deleteCount[, item1[, item2[, ...]]])
Parameters
start
Index at which to start changing the array. If greater than the
length of the array, actual starting index will be set to the length
of the array. If negative, will begin that many elements from the end.
deleteCount
An integer indicating the number of old array elements to
remove. If deleteCount is 0, no elements are removed. In this case,
you should specify at least one new element. If deleteCount is greater
than the number of elements left in the array starting at start, then
all of the elements through the end of the array will be deleted.
itemN
The element to add to the array. If you don't specify any
elements, splice() will only remove elements from the array.
Returns
An array containing the deleted elements. If only one element is
removed, an array of one element is returned. If no elements are
removed, an empty array is returned.
See also Array.prototype.concat()
var elem = $("body")
, msg = function() {
return "<br />"
+ "queue length:"
+ $(this).queue("abc").length
};
elem.queue("abc", [
function(next) {
$(this).append(msg.call(this));
next()
},
function(next) {
$(this).append(msg.call(this));
next()
},
function(next) {
$(this).append(msg.call(this));
next()
}
]);
elem.append(msg.call(elem));
// do stuff,
// replace `function` within `abc` queue,
// change `easing` options within replacement function
elem.queue("abc").splice(1, 1, function(next) {
$(this).append("<br />"
+ "`function` at index `1` within `abc` queue "
+ "replaced with new `function`"
+ msg.call(this));
next()
});
elem.append("<br />"
+ "after `.splice()` , before `.concat()`"
+ msg.call(elem));
// do stuff,
// `concat` functions onto `abc` queue`
var arr = elem.queue("abc").concat(
function(next) {
$(this).append(msg.call(this));
next()
}, function(next) {
$(this).append(msg.call(this));
next()
}, function() {
$(this).append(msg.call(this)
+ "<br />"
+ "done");
}
);
elem.queue("abc", arr);
elem.append("<br />"
+ "after `.concat()`"
+ msg.call(elem));
elem.dequeue("abc");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
i tried, you can do it with create new (re-ordered) queue
download source http://api.jquery.com/queue/
Example: Set a queue array to delete the queue.
and replace start event with my, its worked.
But functions in queue are stored in array of functions. You need to know order of original queue of animations which you want to changed :( Or you can create new optimalized queue.
$( "#start" ).click(function() {
$( "div" )
.show( "slow" )
.animate({ left: "+=50" }, 5000 )
.animate({ top: "+=50" }, 5000 )
.queue(function() {
$( this ).addClass( "newcolor" ).dequeue();
})
.animate({ left: '-=50' }, 1500 )
.queue(function() {
$( this ).removeClass( "newcolor" ).dequeue();
})
.slideUp();
// get current queue
var currQueue = $( "div" ).queue( "fx");
// create new queue and change order or add/remove animations
var newQueue = [];
newQueue.push(currQueue[1]);
newQueue.push(currQueue[3]); // changed
newQueue.push(currQueue[2]); // changed
newQueue.push(currQueue[5]);
// set new queue to element
$("div").queue("fx", newQueue);
console.log($("div").queue("fx"));
});
more info found in jquery documentation
.queue( [queueName ], newQueue )
Description: Manipulate the queue of functions to be executed, once for each matched element.
important is second parameter newQueue
i hope it helps
Related
I have an application that populates the array continuously until it is stopped and it does two things:
If you click Stop button, it writes values in the DB.
Every 1000sec it checks the size of array and if it is > 2000 write the values in the db.
Now I have a problem:
I use the first element of the array to do some calculations, before writing the data to the db.
So if the array exceeds the size of 2000, it performs a splice and passes the array to another page, taking the first element as the basis for the calculation that will be performed on the next page.
At this point, if the user clicks the stop key as the basis for the operations, the last element of the array previously passed must be used.
For example:
array = [0, 20, 40, ......, 2000,..]
array.length > 2000
arrayBase = 0 // I use it for operations.
// Do a splice
array = [2020, 2040, ...... ]
array.length < 2000
//User click stop Button
//I should pass as arrayBase the last value of array (2000)
I hope at least I have explained myself by example.
This is my code:
//this function populate array until I click stop
populateArray(){
this.arrayTimestamp.push(`${buf.readInt16LE(0)}`);
this.firstElementTimestamp = this.arrayTimestamp[0];
//.....
}
//This function check the size and write in the DB if > 2000
checkSize(){
that.timeout = setInterval(function() {
if( (that.arrayTimestamp.length > 2000 ){
that.arrayTimestampCopy = that.arrayTimestamp.splice( 0, 2000 );
//this is a function in other page where I do some operations
scrittura.write({
counterTimestamp: that.firstElementTimestamp,
//...
})
.then(response => {
//...
})
// I have tried something like this:
that.firstElementTimestamp = that.arrayTimestamp[2000] //obviously it is undefined as the array with the splice has been emptied
}, 1000);
}
//this is the function when the Stop button is clicked.
stopConnection(){
Actions.Activity({
counterTimestamp: this.firstElementTimestamp,
//...
})
}
So my goal is to find a way to always use the same base in the calculations, without it being updated.
How can I do?
I think you should use array reduce or Promise All (based on which one you need, parallel or not)
arr.reduce((prom, item) => {
return prom.then(() => {
return scrittura.write(item).then((result) => ... );
});
}, Promise.resolve()).then(function() {
// all done here
}).catch(function(err) {
// error here
});
or use Promise All for parallel
You can see another example here
Synchronous loop in Promise all
Let me explain my situation:
I've 3 positions where images can be hold. They don't have to be filled all.
Empty div | Img 1 | Img 2
When I change the Img 1 to the second place it would be:
Empty div | Img 2 | Img 1
Sortable works fine with this. But I want to save this to the database. The empty div has no ID or data which I want to use. I only want to use the Img's data. So the Img has a data-imgId attribute or something which I want to pass in an array with Javascript.
I want that in my array the "Current position" and the "Data-imgId" are added.
Something like this:
Array
(
[230] = 2
[120] = 1
)
The 230 and 120 are the imageId's and the 2 and 1 are the sortId's. Now I just can update my database with the where clause on the imageId and then set the sortId on the good sort.
With the next code I can check the item which is moved, but the "automatically" moved other image is not returned. How can I fix this:
$( "#pages" ).sortable({
helper: "clone",
update: function(event, ui) {
console.log($(ui.item).attr("id"));
console.log($(ui.item).index() + 1);
}
});
This code returns the id and the position of the dragged object. But I also want to retrieve the other auto moved image id and new position so I can use that for my Database?
Instead use sort(event, ui) which will give you additional information such as the new and original positions of the sorted item. You can then iterate over your array, reassigning position indexes based on these values.
http://api.jqueryui.com/sortable/#event-sort
UPDATE
Apologies, it seems the API no longer includes the before and after indexes. Instead you can use both the start(event, ui) and stop(event, ui) events, and record down the before and after indexes yourself using $(ui.item).index(). After you know these, you can then iterate over your original array, sorted by index position, and update the indexes accordingly.
UPDATE 2
Try this:
$("#pages").sortable({
stop: function(event, ui) {
$("#pages > img").each(function(i, item) {
var id = $(this).attr("id");
array[id] = i;
});
});
});
UPDATE 3
The following revision caters for multiple items, initialised by the classname sort.
var array = { One : {}, Two: {} };
$(".sort").sortable({
stop: function(event, ui) {
var id = $(this).attr("id");
$(this).children().each(function(i, item) {
var itemid = $(item).attr("id");
array[id][itemid] = i;
});
console.log(array)
}
});
See my fiddle.
I'm trying to remove an item from a mootools sortable list, then serialize and save the new list.
I'd like to use a little bit of eye-candy rather than a straight destroy() on the element. I've built a fiddle here: http://jsfiddle.net/kBAqJ/4/
Note the order1 and order2 vars. This holds the serialized element before and after removing the item. If you use the destroy method to get rid of the element after removing it from the sortable, you get the right value for order2, eg. 4.
If you use nix(true) instead of destroy, you get 5 as the value of order1 and order2, even though the docs say that nix(true) calls destroy after dissolve.
Is this a bug in Mootools, or am I missing something? Is there a different way to add a dissolve effect while still using destroy that will get the right result?
window.addEvent('domready', function(){
var mySort = new Sortables('#example2 UL', {
clone: true,
revert: true,
opacity: 0.7
});
console.log (mySort.elements.length);
var order1 = mySort.serialize(0);
console.dir(order1);
mySort.removeItems($('item1')).destroy(); // this results in the correct value in the order2 var below
//mySort.removeItems($('item1')).nix({duration: 1000}, true); // this results in the wrong value for order2
console.log (mySort.elements.length);
var order2 = mySort.serialize(0);
console.dir(order2);
});
i don't think you'll find any effect or way which will destroy the element and still show it on the page ;) So it is not a moo tools bug
The serialize function is using the children of the list (ie. the <li> blocks) to make the array.
I would say the easiest way would be to get rid of their reference in the serialized array:
window.addEvent('domready', function(){
var mySort = new Sortables('#example2 UL', {
clone: true,
revert: true,
opacity: 0.7
});
console.log (mySort.elements.length);
var order1 = mySort.serialize(0);
console.dir(order1);
//mySort.removeItems($('item1')).destroy(); // this results in the correct value in the order2 var below
mySort.removeItems($('item1')).nix({duration: 1000}, true); // this results in the wrong value for order2
console.log (mySort.elements.length);
var order2 = mySort.serialize(0).erase("item1"); // we have to erase the item because he may still be in the list of children at this timeā¦
console.dir(order2);
});
Cheers
I've looked through the other questions about this and not found a suitable answer.
What I need is very simple: The index of the currently shown item.
Here's my little chunk of config
$('.carousel').jCarouselLite(
{
btnNext: "#right-navigation",
btnPrev: "#left-navigation",
visible: 1,
afterEnd: function(a)
{
// Code that requires the index
}
});
Note: the a is an object
Thanks!
The elements representing the items
that are visible after the animation
ends are passed in as argument.
so you should be able to do something like
afterEnd: function(a){
var index = $(a[0]).index();
}
to get the index of the first element
I used Firefug to profile my web application and found that the following function is called, and needs to be called, literally hundreds of times per user visit. So I want to optimize it since Firebug says it uses the most resources/times.
function highlightChildDiv(parentDiv) {
/* find the closest (hlisting) home listing to the middle of the scrollwindow & highlight */
var scrollElemPos = parentDiv.offset();
var highlightDiv = $(document.elementFromPoint(
scrollElemPos.left + parentDiv.width() / 2,
scrollElemPos.top + parentDiv.height() / 2)
).closest('#parentDiv div.childClass');
if (highlightDiv.hasClass("HighlightRow")) {
return; // if the div is already highlighted, return
} else {
$('#parentDiv div.childClass').removeClass("HighlightRow");
highlightDiv.addClass('HighlightRow');
}
}
Seems to me that one of the most un-optimized statements is .closest('#parentDiv div.childClass');, but I'm sure there is other things to improve.
Question: Does anyone have any JQuery performance tips on how I can optimize the code above given that this function is run literally hundreds of times per user visit.
First thought, eliminate the dead statement in the if clause.
if (!highlightDiv.hasClass("HighlightRow")) {
$('#parentDiv div.childClass').removeClass("HighlightRow");
highlightDiv.addClass('HighlightRow');
}
In the selector #parentDiv div.childClass, can you guarantee that div will be a direct descendent of #parentDiv? In which case:
.closest('#parentDiv>div.childClass');
and
$('#parentDiv>div.childClass')
You already have parentDiv. I'm guessing this is a DOM object, so you may be able to do the following:
$(parentDiv).children("div.childClass")
Just hide the DIV that is currently highlighted:
$('#parentDiv div.HighlightRow').removeClass("HighlightRow");
My guess is this is the most unoptimized line:
$('#parentDiv div.childClass').removeClass("HighlightRow");
You should profile it to make sure (create a date object outside the call and output the getTime() value before and after each call).
Here you are asking jQuery to iterate over all DOM elements that match that selector and remove the class. If there are 1000 rows, jQuery will need to interogate each one to see if it needs to remove a class. Ugh. Here it is with that lookup removed:
// namespace scoped cache
var Hash_$_Cache = {
$parentDiv : $('#parentDiv'),
$tgt_row : $([]) // empty jq object to start
};
// find the closest (hlisting) home listing to the middle of
// the scrollwindow and highlight
//
var highlightChildDiv = function (parentDiv){
var
scrollElemPos = parentDiv.offset(),
$tgt_row
;
$tgt_row = $(document.elementFromPoint(
scrollElemPos.left + parentDiv.width() / 2,
scrollElemPos.top + parentDiv.height() / 2)
).closest('#parentDiv div.childClass')
;
// bail if row is already highlighted
if ($tgt_row.hasClass('HighlightRow')){ return; }
Hash_$_Cache.$tgt_row.removeClass('HighlightRow');
$tgt_row.addClass('HighlightRow');
// save highlighted row for later
Hash_$_Cache.$tgt_row = $tgt_row; // store new row in cache
};
Hope that helps!
I prefer to use the following methodology:
https://gist.github.com/3841424#file-domcache-js
Or, you may replace the DOM object with a method in this implementation:
var myNS = {
myEventHandler: function(event){
this.DOM.$el.doSomething();
},
cacheDOM: function(){
return {
$el: $("#matrix")
};
},
initialize: function(){
this.DOM = this.cacheDOM();
}
};