CSS3 animationStarted event trigger with a delay of 25/30 milliseconds - javascript

i have made a JSFiddle to show the problem
http://jsfiddle.net/molokoloco/yvTje/
In few words, i put some listener on the animationStart event, add a new class to the element and then, in a plugin i do, i need to check if the element have an animation (can be associated with the class) before doing, or not, something.
My probleme is i have to wait 25/80 millisecond before it's possible to check if an animation is started or not...
Something i do bad or any suggestion ?
var animationStarted = false,
s = '';
var listener = function(e) {
switch (e.type) {
case "animationstart":
case "webkitAnimationStart":
// BUT "animationstart" do not trigger instantaneously
// For the moment i compute 25 milliseconds on my Chrome & FF
var diff = (new Date().getTime()) - s;
console.log('animationStarted after ' + diff + ' ms'); // HERE THE RESULT : 30ms
break;
}
};
var setup = function() {
var e = document.getElementById("watchme");
e.addEventListener("animationstart", listener, false);
e.addEventListener("webkitAnimationStart", listener, false);
// HERE WE ADD THE CLASS
e.className = "slidein";
s = new Date().getTime(); // Time at witch the class (with anim) is applyed
};
setup();

Use feature detection even before you try to start the animation.
var div = document.createElement("DIV");
div.style["animation"] = "animName 5s infinite";
div.style["WebkitAnimation"] = "animName 5s infinite";
if (div.style["animationDuration"] == "5s") {
// Supports animation
} else (div.style["WebkitAnimationDuration"] == "5s") {
// Supports -webkit-animation
}
This tests for the browser's ability to set individual style attributes using shorthand. If you just set a value and read it back the same way, you'll get false positives.
EDIT: Sorry, misunderstood the problem.
Regarding using events to check for stuff, you will probably have to wait a few milliseconds, no matter what you do... You could check the style definitions themselves using document.styleSheets, but that would be pretty exhausting, depending on the specificity of the css.
var animationName = "";
for (var i = 0; i < document.styleSheets.length; ++i) {
var sheet = document.styleSheets[i];
var rules = sheet.cssRules || sheet.rules;
for (var j = 0; j < rules.length; ++j) {
var rule = rules[j];
if (theElement.matchesSelector(rule.selectorText)) {
var theStyle = rule.style;
animationName = theStyle["WebkitAnimationName"];
}
}
}
It's a pretty crude way of doing this, I know...

Related

Can't find the way to proper timeout or interval

I can't find the way to timeout or pause (tried for and counting to big numbers) click event. I use alert('x') to stop before $(arr[i-1]).click(); and then I have to press enter after that. But I want to automically pause after click event for about 300 ms.
javascript:
var arr = $("a.farm_icon_b");
var x = document.getElementById("plunder_list").rows;
var images;
for (var i = 0; i < x.length; i++) {
var z = x[i].id;
if (!!z) {
images = document.getElementById(String(z)).getElementsByTagName('img');
for (var j = 0; j < images.length; j++) {
if (!!images) {
if (images[j].src == "https://dspl.innogamescdn.com/8.116/36249/graphic/command/attack.png") {
if (images[j].tooltipText == "1 atak w drodze") {
alert('x');
$(arr[i - 1]).click();
} else if (images[j].tooltipText == "2 ataki w drodze") {
alert('y');
$(arr[i - 1]).click();
}
}
}
}
}
}
You can use javascript setTimeout function to hold or stop your script to execute for time as per your requirement. check this Link for more details. All the best.
setTimeout(function(){
$(arr[i - 1]).click();
}, 3000); // 3000 is stands for 3 second you can change it according to your requirementcode here
Important Note (thanks to #Thomas for highlighting this) This function doesn't "sleep" for 300ms, it freezes the page. The browser simply is stuck in that loop for 300ms and can't do anything untill this is over.
I think this is the function you are looking for. It will help you put a 300ms delay before the button clicks.
function pausecomp(millis)
{
var date = new Date();
var curDate = null;
do { curDate = new Date(); }
while(curDate-date < millis);
}
Source: http://userscripts-mirror.org/scripts/review/408779
Usage:
pausecomp(300); // Sleep for 300ms
$(arr[i - 1]).click();
Disclaimer:
Ideally, a setTimeout() based solution is the best approach for such problems in Javascript (as suggested by Akansh). However, a linear for-loop based approach will most likely not work for such a solution, and you will need to devise a callback functions based solution that relies on deferred execution.

Javascript Loop with Sleep

I have a gridview and a dropdownlist in my ASP in the C# i have functionality that will allow the user to select which dropdownlist item will apply to each gridview row.
so in the JavaScript i want slideshow like functionality for each dropdownlist item and count how many gridview rows contain that item.
I'm attempting to get the code to run at a consistent speed (2 seconds per dropdownlist item)
Below is my JavaScript
$(document).ready(function () {
loop();
});
function loop() {
var ddl = document.getElementById("cphMain_ddlInc");
for (var j = 1; j < ddl.options.length; j++) {
setTimeout(shippedEmbryos(j), 2000);
}
}
function shippedEmbryos(j) {
var st = $("input[id*=txtShipped]");
var grid = document.getElementById("cphMain_gvFertEntry");
var ddl = document.getElementById("cphMain_ddlInc");
var embryos = 0;
var ddlValue = ddl.options[j].innerHTML;
for (var i = 1; i < grid.rows.length - 1; i++) {
if (ddlValue == grid.rows[i].cells[2].innerHTML) {
var txtbox = $("input[id*=txtShipped]");
var x = txtbox[i].value;
if (x == "") {
x = 0;
}
}
else {
x = 0;
}
embryos += parseInt(x);
}
var label = document.getElementById("cphMain_lblShippedEmbryos");
label.innerHTML = "Embryos Shipped for " + ddlValue + ": " + embryos;
};
JavaScript doesn't work like that ...
The language is single-threaded, which means that if you sleep for two seconds everything is locked up while you do. That includes your current window -- everything you are trying to draw on screen.
In many browsers all windows freeze.
You need to do event-driven programming here where you fire off an event to draw the next lie.
There are a number of work-arounds depending on if you can use ES7 await/async through a cross compiler or if you can use ES6's Promises. Lastly ES5 gives you setTimeout
What is the JavaScript version of sleep()?
If you want to wait some time in JS, you can't keep looping because it would block thread.
You could use setTimeout method instead or you can use Window.requestAnimationFrame() method, it would fit in your current code better.
Here is draft(modified from MDN sample code)
var start;
function step(timestamp) {
var progress;
if (start === null) start = timestamp;
progress = timestamp - start;
// trigger every 2000ms, equal 2s
if (progress >= 2000) {
//reset start time
start = timestamp;
// do whatever you want ..., such as call shippedEmbryos()
//start another loop
requestAnimationFrame(step);
}
}
MDN:Window.requestAnimationFrame()- This method call every frame and it is browser friendly API(would not affect page rendering performance).
It has one argument : timestamp, browser system would pass current timestamp in automatically.
look like this: 55378.47799999872 55395.189000002574 55411.900000006426....
Then you can keep call the method like recursive.
If you want to stop, just simply not call the method.

Vanilla JS: delay click event to add animation

No jQuery please!
I would love not to use jQuery for this, because it's a big library and I only need to do this single thing:
I would like to add a short delay to a click event so I can fade elements off my page using CSS.
I could post all of the code I've tried so far, but you'd get bored. So here's the one that I think is the closest:
document.getElementsByTagName('a').onclick = function (e) {
// Delay setting the location for one second
setTimeout(function() {this.href}, 90000);
var animOut = document.getElementByClassName('animateOut');
animOut.className += 'out';
};
I've already ruled out using onbeforeunload, so hijacking the click event seems to be the best way.
Once again, I know this would be a doddle in jQuery, but I would like to avoid it if it's possible.
Thanks so much for your answers.
Ben
UPDATE
Thanks to commenters guest271314 and The Alpha, I've settled on this approach, but still have yet to complete the puzzle.
window.onload = function(){
var links = document.getElementsByTagName('a');
for( var i=0,il = links.length; i< il; i ++ ){
links[i].onclick = clickHandler;
}
function clickHandler(event) {
event.preventDefault();
// Delay setting the location for one second
setTimeout(function() {
location.href = this.href;
}, 90000);
// add `s` to `Element`
var animOut = document.getElementsByClassName("animateOut");
// iterate `animOut` elements
for (var i = 0; i < animOut.length; i++) {
// add `out` `className` to `animOut` element at index `i`
animOut[i].classList.add("out");
};
};
};
Having to iterate over the a tags was an addition I have learned from reading other posts (I'll link to them in a minute).
Unfortunately, the setTimeout function doesn't seem to be working. I need to refine what's in this function, but don't know in what way.
Further assistance would be most welcome.
Thanks
Ben
I can't really take credit for this, the 2 users below (guest271314 and The Alpha) deserve a lot of recognition for what they helped me to achieve. The full code, with a couple of refinements, is:
window.onload = function(){
var links = document.getElementsByTagName('a');
for( var i=0,il = links.length; i< il; i ++ ){
links[i].onclick = clickHandler;
}
function clickHandler(event) {
event.preventDefault();
var travelTo = this.getAttribute("href");
// add `s` to `Element`
var animOut = document.getElementsByClassName("animateOut");
// iterate `animOut` elements
for (var i = 0; i < animOut.length; i++) {
// add `out` `className` to `animOut` element at index `i`
animOut[i].classList.add("out");
};
// Delay page out until the animation finishes
setTimeout(function() {
window.location.href = travelTo;
}, 1000);
};
};
You may try something like this:
document.getElementsByTagName('a').onclick = function (event) {
event.preventDefault();
document.getElementByClassName('animateOut').className += ' out';
setTimeout(function() {
location.href = this.href;
}, 1000);
};
There should be an "s" at document.getElementsByClassName . To add className to all animateOut elements can use a for loop; change this.href to window.location.href = e.target.href if expected result is to navigate to href of clicked a element; else leave as this.href is requirement is to refresh current window.location.href : this.href within setTimeout
document.getElementsByTagName("a").onclick = function (e) {
// Delay setting the location for one second
setTimeout(function() {window.location.href = this.href}, 90000);
// add `s` to `Element`
var animOut = document.getElementsByClassName("animateOut");
// iterate `animOut` elements
for (var i = 0; i < animOut.length; i++) {
// add `out` `className` to `animOut` element at index `i`
animOut[i].classList.add("out");
};

How to stop all timeouts and intervals using javascript? [duplicate]

This question already has answers here:
javascript: Clear all timeouts?
(13 answers)
Closed 6 years ago.
I'm working on an ajax web appliation which contains many running timeouts and intervals. And now I need to clear all running timeouts and intervals sometimes. Is there a simple way to stop everything without need to store every timeout and interval ID and iterate through them and clear them?
Sometimes it's possible to save the timer Id / Handle to clear it later which would be the best solution. So this is a second best. But I wanted to give a better understanding of what's going on. It basically grabs the highest timer id and clears everything less than that. But it's also possible to clear other timers that you do not want to clear!
It is a little hackish, so be warned!
// Set a fake timeout to get the highest timeout id
var highestTimeoutId = setTimeout(";");
for (var i = 0 ; i < highestTimeoutId ; i++) {
clearTimeout(i);
}
Updated answer after reading the duplicate I closed this question with -
It works and tested in Chrome on OSX
// run something
var id1 = setInterval(function() { console.log("interval", new Date())}, 1000);
var id2 = setTimeout(function() { console.log("timeout 1", new Date())}, 2000);
var id3 = setTimeout(function() { console.log("timeout 2", new Date())}, 5000); // not run
setTimeout(function() { console.log("timeout 3", new Date())}, 6000); // not run
// this will kill all intervals and timeouts too in 3 seconds.
// Change 3000 to anything larger than 10
var killId = setTimeout(function() {
for (var i = killId; i > 0; i--) clearInterval(i)
}, 3000);
console.log(id1, id2, id3, killId); // the IDs set by the function I used
NOTE: Looked at window objects that had a typeof number - funnily enough IE assigns an 8 digit number, FF a single digit starting with 2
Here is a workaround.
window.timeoutList = new Array();
window.intervalList = new Array();
window.oldSetTimeout = window.setTimeout;
window.oldSetInterval = window.setInterval;
window.oldClearTimeout = window.clearTimeout;
window.oldClearInterval = window.clearInterval;
window.setTimeout = function(code, delay) {
var retval = window.oldSetTimeout(code, delay);
window.timeoutList.push(retval);
return retval;
};
window.clearTimeout = function(id) {
var ind = window.timeoutList.indexOf(id);
if(ind >= 0) {
window.timeoutList.splice(ind, 1);
}
var retval = window.oldClearTimeout(id);
return retval;
};
window.setInterval = function(code, delay) {
var retval = window.oldSetInterval(code, delay);
window.intervalList.push(retval);
return retval;
};
window.clearInterval = function(id) {
var ind = window.intervalList.indexOf(id);
if(ind >= 0) {
window.intervalList.splice(ind, 1);
}
var retval = window.oldClearInterval(id);
return retval;
};
window.clearAllTimeouts = function() {
for(var i in window.timeoutList) {
window.oldClearTimeout(window.timeoutList[i]);
}
window.timeoutList = new Array();
};
window.clearAllIntervals = function() {
for(var i in window.intervalList) {
window.oldClearInterval(window.intervalList[i]);
}
window.intervalList = new Array();
};
It works for set/clear timeout/interval functions called after these lines are executed. Try and see it works:
setInterval('console.log(\'a\')', 1000);
setInterval('console.log(\'b\')', 500);
setInterval('console.log(\'c\')', 750);
setTimeout('clearAllIntervals()', 10000);
Proxying does the magic.
var noofTimeOuts = setTimeout('');
for (var i = 0 ; i < noofTimeOuts ; i++) clearTimeout(i);
var max = setTimeout(function(){ /* Empty function */ },1);
for (var i = 1; i <= max ; i++) {
window.clearInterval(i);
window.clearTimeout(i);
if(window.mozCancelAnimationFrame)window.mozCancelAnimationFrame(i); // Firefox
}
There's nothing built-in, but it's pretty easy to blast through all currently outstanding deferred execution functions by calling this clearAll() function:
function clearAll() {
for (var i = setTimeout(function() {}, 0); i > 0; i--) {
window.clearInterval(i);
window.clearTimeout(i);
if (window.cancelAnimationFrame) window.cancelAnimationFrame(i);
}
}
If you are in charge of the page you run, and can wrap the native deferred execution functions in wrappers that do the house keeping for of course equip each setter function with a corresponding .clearAll() too:
(function(deferFunctions) {
for (var setter in deferFunctions) (function(setter, clearer) {
var ids = [];
var startFn = window[setter];
var clearFn = window[clearer];
function clear(id) {
var index = ids.indexOf(id);
if (index !== -1) ids.splice(index, 1);
return clearFn.apply(window, arguments);
}
function set() {
var id = startFn.apply(window, arguments);
ids.push(id);
return id;
}
set.clearAll = function() { ids.slice(0).forEach(clear); };
if (startFn && clearFn) {
window[setter] = set;
window[clearer] = clear;
}
})(setter, deferFunctions[setter]);
})(
{ setTimeout: 'clearTimeout'
, setInterval: 'clearInterval'
, requestAnimationFrame: 'cancelAnimationFrame'
});
To try that it works, you could then try doing this, for instance, which will remain silent, as none of the callbacks end up firing before they're cancelled again:
// Some example timers of all types:
requestAnimationFrame(console.error);
setInterval(console.info, 1000, 'interval');
setTimeout(alert, 0, 'timeout');
// Now you can clear all deferred functions
// by execution type, whenever you want to:
window.setTimeout.clearAll();
window.setInterval.clearAll();
window.requestAnimationFrame.clearAll();
A little hack added to Gokhan Ozturk's answer
If you are using third party libraries which uses Timeouts and Intervals then they will also be cleared, so I added one parameter to notify function that this interval is to be push'ed or not to array.
window.setTimeout = function(code, delay, toBeAdded) {
var retval = window.oldSetTimeout(code, delay);
var toBeAdded = toBeAdded || false;
if(toBeAdded) {
window.timeoutList.push(retval);
}
return retval;
};
... // likewise for all functions.
You might be better off creating a scheduler. Take a look at this approach by Nader Zeid:
https://www.onsip.com/blog/avoiding-javascript-settimeout-and-setinterval-problems
It's an approach that help create some determinacy (because "the time interval argument of each of those functions really only establishes that the given function will execute after at least that amount of time. So a timed event can miss its target by literally any amount of time.").
Specifically, to the question you raise here, you can easily add and remove functions from the queue. While this response is long after the question was raised, hopefully it's helpful to any who find themselves struggling with Timeouts and Intervals.
You cannot clear any timeouts and intervals you don't know about.
You'd need something like getTimeoutList which isn't in the DOM3 spec, or even planned, AFAIK.
The previous proxying trick is nice, but if you have a lot of timeouts and intervals, I would not fill the arrays with consecutive numbers [1,2,3....], but with intervals. For example, instead of having [1,2,3,7,8,9], you would have maybe something like ['1-3','7-9'] or [[1,3],[7,9]], as a memory optimization. Of course this trick is only suited if you have a lot of timeouts and intervals and also if you would not stop arbitrary intervals that often.

How to use setTimeout / .delay() to wait for typing between characters

I am creating a simple listbox filter that takes the user input and returns the matching results in a listbox via javascript/jquery (roughly 5000+ items in listbox). Here is the code snippet:
var Listbox1 = $('#Listbox1');
var commands = document.getElementById('DatabaseCommandsHidden'); //using js for speed
$('#CommandsFilter').bind('keyup', function() {
Listbox1.children().remove();
for (var i = 0; i < commands.options.length; i++) {
if (commands.options[i].text.toLowerCase().match($(this).val().toLowerCase())) {
Listbox1.append($('<option></option>').val(i).html(commands.options[i].text));
}
}
});
This works pretty well, but slows down somewhat when the 1st/2nd char's are being typed since there are so many items.
I thought a solution I could use would be to add a delay to the textbox that prevents the 'keyup' event from being called until the user stops typing. The problem is, I'm not sure how to do that, or if its even a good idea or not.
Any suggestions/help is greatly appreciated.
You can do a delay like this:
$('#CommandsFilter').keyup(function() {
clearTimeout($.data(this, 'timer'));
var wait = setTimeout(search, 500);
$(this).data('timer', wait);
});
function search() {
var temp = $("<select />");
for (var i = 0; i < commands.options.length; i++) {
if (commands.options[i].text.toLowerCase().match($(this).val().toLowerCase())) {
$('<option></option>', { val: i, html: commands.options[i].text }).appendTo(temp);
}
}
Listbox1.empty().append(temp.children());
}
This stores a timeout on the element you're typing in, if 500ms (adjust as needed) passes between keystrokes, a search executes. Also this appends the elements in a document fragment then into the DOM (still preserving encoding, etc). Depending on the number of items, this may be a decent performance boost as well.
If the commands drop-down isn't changing, I'd suggest the following (note I've dropped jQuery for better performance and compatibility). There are several improvements:
Timer to delay updating the filtered list once half a second has elapsed since the last keypress
List of command texts is pre-cached
Unnecessary use of match replaced with indexOf
Uses fast native DOM manipulation that works in all scriptable browsers since the 1990s
A quick test suggests that for a drop-down with 5000 options containing short strings, it's between 10 and 30 times faster than the jQuery equivalent in most browsers.
Code:
var commands = document.getElementById("DatabaseCommandsHidden");
var filteredDropDown = document.getElementById("Listbox1");
var filterInput = document.getElementById("CommandsFilter");
var timer;
// Create a cached list of the lower case text of the commands drop-down
var commandTexts = [], commandText;
for (var i = 0, len = commands.options.length; i < len; ++i) {
commandText = commands.options[i].text;
commandTexts.push({original: commandText, lower: commandText.toLowerCase()});
}
function populateFilteredDropDown() {
timer = null;
var val = filterInput.value.toLowerCase(), commandText;
var opts = filteredDropDown.options;
filteredDropDown.length = 0;
for (var i = 0, len = commandTexts.length; i < len; ++i) {
commandText = commandTexts[i];
if (commandText.lower.indexOf(val) > -1) {
opts[opts.length] = new Option(commandText.original);
}
}
}
filterInput.onkeyup = function() {
if (timer) {
window.clearTimeout(timer);
}
timer = window.setTimeout(populateFilteredDropDown, 500);
};

Categories

Resources