Improvements in JavaScript animation - javascript

I am trying to create a train station text effect.
You can see here what i have achieved so far: http://www.jaspreetkaur.com/chatter/
here's the code, for your reference: http://jsfiddle.net/alokjain_lucky/ARhvu/
Issues:
The effect is running very slow, not giving it a very smooth and realistic effect.
Not working in IE7
I think the script i have created can be improved.
Please provide your expert advise to resolve the issues.
Thanks :)
Update:
The script is for the animation of text "Get to the chatter that matters"
Following is the Javascript code i have used:
$(document).ready(function() {
var newSrt = '';
for (var i=0; i<str.length; i++) {
if (str[i] != ' ') {
newSrt += '<span>'+str[i]+'</span>';
//newSrt += '<span> </span>';
} else {
newSrt += '<span class="nobg">'+str[i]+'</span>';
//newSrt += '<span class="nobg"> </span>';
}
}
$('.animate').html(newSrt);
scroll();
});
var str = ('The quick brown fox jumps over the lazy dog').toUpperCase();
var symtype=new Array(" ","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z");
var symarray=new Array();
for (var i=0; i<str.length; i++){ symarray[i]=" "; }
function scroll(){
for (var i=0; i<str.length; i++){
if (symarray[i]!=str.substring(i,i+1)) {
for (var x=0; x<symtype.length; x++) {
if (symarray[i]==symtype[x]) {
symarray[i]=symtype[x+1];
break;
}
}
}
}
for (var i=0; i<str.length; i++) {
$('.animate').find('span').eq(i).html(symarray[i]);
}
setTimeout('scroll()',10);
}
I hope this describes the code batter.
Update 2
Script is working in IE7 now, it's too fast on all browsers, i can make it slow by changing the setTimeout, but it's too slow in Firefox (only), I am using Firefox 9.0.1
Update 3
Surprisingly firebug is making the script slow in Firefox, turning firebug off, resolves the speed issue in Firefox.
in IE7 issue is related to CSS, which i think i will be able to resolve.
The only think left is to improve the script to make it reusable for other places in the website.

I fixed up your jsFiddle here: http://jsfiddle.net/jfriend00/VWXFp/ to make it run and it appears to work now, even in IE.
I moved the $(document).ready() block to the end so the globals are defined first which was only required because of the way you had the jsFiddle configured.
I changed to setTimeout(scroll,100); to use the direct function reference rather than a text string.
I changed the timeout vale on the timer to 100ms
I changed the jsFiddle setting in the upper left to "no wrap (body)"
I changed your letter setting loop to be massively more efficient. You were re-finding ever single letter span for every single letter rather than finding them all once and just looping through them. This could have been a performance issue in some browsers.
For #5, I changed from this:
for (var i=0; i<str.length; i++) {
$('.animate').find('span').eq(i).html(symarray[i]);
}
to this:
$('.animate').find('span').each(function(index, element) {
$(this).html(symarray[index]);
});
Which evaluates $('.animate').find('span') only once instead of str.length times.

Related

Taking long time to load selectBox

Below code snippet, "for" loop is taking long time to load the data to select box, could any one help me ? even I am using Jquery 1.3.2 which is new to me.
here names.response.length is 120000 records.
function personNameChangedCallback(names){
if(names.response.length > 0){
var options = [];
for (var i = 0; i< names.response.length; i++) {
options.push('<option>'+ names.response[i] +'</option>');
}
jQuery('[id=personNameSelected]').append(options.join(''));
}
What could help is to avoid using an array to store the options and instead concatenate the strings directly.
Here is a jsperf comparison for this, using array is around 80% slower than directly concatenating a string:
https://jsperf.com/javascript-test-string-concat-vs-array/1
So you can change your function like this:
function personNameChangedCallback(names){
if(names.response.length > 0){
var htmlOptions = '';
for (var i = 0; i< names.response.length; i++) {
htmlOptions += '<option>'+ names.response[i] +'</option>';
}
jQuery('[id=personNameSelected]').html(htmlOptions);
}
The reason why it is slow in Internet Explorer, is because it's Javascript engine is not as advanced as the ones of other browsers.
Internet Explorer will also have issues letting you scroll through all these options.
Using a suggestion box as already mentioned by someone else is a better option, especially when your applciation has to be compatible with Internet Explorer.

Measure what part of a loop that is slow?

I'm looping through a dataset with a couple of thousand items in it like this.
users.forEach(function(user){
//List ALLTHETHINGS!
listAllEverything(user)
//Add gropings
user.groupings = groupings.filter(function(grouping){
return grouping.conditional(user)
})
//Add conversions to user, one per user.
user.conversions = {}
//for each conversionList
conversionLists.forEach(function(conversionList){
user.conversions[conversionList.name] = [];
//for each conversion
for (var i = conversionList.conversions.length - 1; i >= 0; i--) {
var conversion = conversionList.conversions[i]
//test against each users apilog
var converted = user.apilog.some(function(event){
return conversion.conditional(event);
})
if (converted){
//Lägg till konverteringen och alla konverteringar som kommer innan.
for (var i = i; i >= 0; i--){
user.conversions[conversionList.name].push(conversionList.conversions[i])
}
break;
}
};
})
})
I know this is not the most optimized code and I have some ideas how it can be improved. But i'm pretty new to these kinds of problems, so I'm not sure how I should prioritize. I know about console.time, which is useful but I want to use something that allows me to compound the time spent on each part of the forEach-loop, either a tool (I usually use chrome) or some debugging-method. Perferably something that doesn't effect the performance too much.
Since you are using Chrome you shoud check out the Timeline tab in your browsers DevTools - just hit the record button before running the loop and stop it once it's done. You will se a nice breakdown of everything that just happened and you will be mostly interested in yellow bars - they show JavaScript operations.
Please check out this video presentation by Paul Irish about Performance Tooling
As you know, in Chrome or Firefox you can just wrap a piece of code with console.time (and console.timeEnd) and it will measure the speed of particular operation and print it in the console.
For example: to measure the time it takes for an entire loop to execute use:
console.time('For loop benchmark');
for(i=0; i<1000; i++) {
// do some operations here
}
console.timeEnd('For loop benchmark');
But, if you want to measure each iteration you can parameterize the name of the log inside the loop so that you can name each specific operation the way you want:
for(i=0; i<1000; i++)
var consoleTimeName = 'Measuring iteration no '+i+' which is doing this and that...';
console.time(consoleTimeName);
// do some operations here
console.timeEnd(consoleTimeName);
}
Using it you can see for yourself how much faster simple for loop can be in comparsion to jQuery's $.each loop.
You can find more about this on developer.mozilla.org and developer.chrome.com. Please not that this is note a standarized, cross-browser compatibile feature and you should not be using it on a production website, since some browser like IE may throw you an error when they see it.

parentNode not deleting properly

my javascript knowledge is pretty poor. I'm trying to run a script with greasemonkey on http://www.twitch.tv/directory/all to remove certain kinds of streams from the list based on an image provided next to a shot of the stream(like picture of hearthstone, minecraft etc.). Here's the code:
//what you want to remove
var killIt=["http://static-cdn.jtvnw.net/ttv-boxart/Hearthstone%3A%20Heroes%20of%20Warcraft-138x190.jpg", "http://static-cdn.jtvnw.net/ttv-boxart/League%20of%20Legends-138x190.jpg", "http://static-cdn.jtvnw.net/ttv-boxart/Minecraft-138x190.jpg"];
var el = document.getElementsByClassName("boxart");
//runthrough elements killing certain ones
for (i = 0; i < el.length; i++) {
for (j = 0; j < killIt.length; i++) {
if (el[i].src == killIt[j]) {
var ely = el[i].parentNode;
ely.parentNode.removeChild(ely);
}
}
}
So i tried it on w3schools site and the code works fine, but when i try to actually run it in twitch.tv it does nothing(seemingly).
Am i missing something about parent nodes? Or greasemonkey?
The second for should be j++. Also you can use .indexOf to test if the URL is listed in the array to avoid a other for loop.

how does "System.out.println" work in JS?... :)

My background is in java and right now Im getting into learning Javascript. (I'm porting this java code that I made into javascript but it behaves a bit different than I expected?? If I use "console.log()" instead of "document.write" I'm NOT getting the same result..why?
thanks 4 yr time! Some insight will be very appreciated!
var counter = 1;
function println(str) {
console.log(str);//
}
for (var i = 1; i <= 5; i++) {
for (var j = i; j < 5; j++) {
document.write("#");
// println("#");
}
for (var k = 1; k <= counter; k++) {
document.write("*");
// println("*");
}
document.write("<br/>");
//println(" "); <--- "\n" ?
counter+= 2; //
} // ends application
document.write() is for printing content to the page of your document, while console.log() is used predominantly for diagnostic/debug information to be emitted in the console of your web browser. Specifically, document.write() is intended to be consumed by the viewer of your page, while console.log() is generally not.
Console.log logs stuff into browser console. Install Firebug (getfirebug.com) and you will see your logs.
Also there is nice description about how it works http://getfirebug.com/logging.
Also, using document.write is not really elegant, you can use it only on page load, and it's blocking whole page. You basically should not use it at all. If you try to use document.write after page is loaded, it will replace whole content of your document with your last "log".

Sleep function in javascript - without using recursion

First of all, I've had a look on all the 'sleep' questions lying around (such as What is the JavaScript version of sleep()?) but I didn't find an acceptable solution.
I would like to make a visual education tool for all sort of algorithms. In order to do so, I'm using javascript with jQuery to display the data and paint it up nicely. In order to start it up, I want to do a sorting sample, where an array is displayed, shuffled and then sorted in a visually pleasing way. So what I want to happen is that two cells get highlighted (easy), possibly swapped (easy), and then there's a small delay before the next pair is tested (hard).
I understand there isn't an explicit 'sleep' method in javascript. However, to restructure the code into using setTimeout would imply rewriting all my algorithms recursively, which is a huge hinder (although obviously not impossible).
As a sample problem, take a look at a bubble sort sample:
function bubble_sort(arr){
for(var i=0;i<arr.length;i++){
for(var j=1;j<arr.length;j++){
highlight(j-1);
highlight(j);
if(arr[j-1] > arr[j]){
visible_swap(arr, j, j-1);
}
sleep(1000);
}
}
exhibit_array(arr);
}
This can obviously rewritten recursively to work with setTimeout, but to do so on all the algorithms I have in mind would take a great deal of time. Am I missing something? Is there an 'easy' way to leave the implementations as they are and place sleeps at will?
EDIT:
I found two solutions: a pretty one, and a compatible one.
The pretty one only works on firefox, I'm afraid, and makes use of the wonderful yield semantics (There is some sample explanation here: https://developer.mozilla.org/en/New_in_JavaScript_1.7). This actually solves my problem perfectly, thus:
function bubble_sort(arr){
for(var i=0;i<arr.length;i++){
for(var j=1;j<arr.length;j++){
highlight(j-1);
highlight(j);
if(arr[j-1] > arr[j]){
visible_swap(arr, j, j-1);
}
yield true;
}
}
yield false;
}
var bubble = bubble_sort(arr)
function gen(){
if(bubble.next()){
setTimeout(gen, 500);
}
else{
alert("Done!");
}
}
This works wonderfully for me, but does rely on the yield capability which currently is only supported on firefox. Notice that for this to work at all, you need to use <script type="text/javascript;version=1.7">. This however is perfect. It could have also worked for infinite algorithms, showing them toiling in vain if need be.
The second solution I found works as well, based on the answer below:
function bubble_sort(arr){
var q = new Array();
for(var i=0;i<arr.length;i++){
for(var j=1;j<arr.length;j++){
q[q.length] = [ [highlight, j-1 ], [highlight, j] ];
if(arr[j-1] > arr[j]){
swap(arr, j, j-1);
q[q.length] = [ [visible_swap, j, j-1] ];
}
}
}
return q;
}
function play(q, step){
if(q.length == 0)
return;
clear_highlights();
cmds = q.shift();
for(ind in cmds){
cmd = cmds[ind];
f = cmd.shift();
f.apply(null, cmd);
}
setTimeout(function(){ play(q, step); }, step);
}
This works as well. This is pretty bothersome syntactically, but definitely works well on all browsers.
After all this though, it seems there are javascript 'extensions' which implement sleep-like syntax, which is obviously better than all of the above.
Thanks for the help!
Recently I made a visualization of sub-palindrome finder algorithm, it used setTimeout and didn't require rewriting of the algorithm in recursive form.
See this example.
The general principle is to build up a stack of commands, for bubble sort that would be a stack of highlight and swap commands. Then you can have a function running each N milliseconds which takes a command from the stack and visualizes it.
commands = [
['highlight', 1, 5]
['swap', 1, 5]
['highlight', 3, 7]
...
];
setInterval(function() {
var cmd = commands.shift();
visualize(cmd);
}, 1300);
In my problem the finder algorithm was written in Python and was provided by the user, and I couldn't modify it. Fortunately Python allows to overload access and comparison operators and record each action the algorithm takes. RecString class. In JavaScript you can't do that, but that's not a problem in your case, because you can modify the original algorithm.
I can email you the JS source if you want, it was written in haste, but might be useful anyway.
Another idea - StratifiedJS. Here's a simple jsFiddle example:
<script src="http://code.onilabs.com/apollo/0.13/oni-apollo.js"></script>
<script type="text/sjs">
for (var i = 1; i < 4; i++) {
alert(i);
hold(1000);
}
</script>
I would work with setTimeout, I believe that is the closest you are going to get to a "sleep" equivalent on the client-side.
This answer doesn't solve the general case, but perhaps you can increment the interval for each instruction so that they run one second after each other.
function bubble_sort(arr){
var interval = 0; // increases with each loop
for(var i=0;i<arr.length;i++){
for(var j=1;j<arr.length;j++){
(function(i, j) {
setTimeout(function() {
highlight(j-1);
highlight(j);
if(arr[j-1] > arr[j]){
visible_swap(arr, j, j-1);
}
}, interval);
})(i, j);
interval += 1000;
}
}
exhibit_array(arr);
}
Thus, the first operation runs at once, the next runs after one second, the thrid after a total of two seconds, etc.
This solution provides the benefit of minimal code rewriting: just wrap your loop contents in a setTimeout (which is wrapped inside a closure with your loop variables) and add a line to increment interval after each loop iteration.
Using setTimeout() is not recursion.
You can work with a closure to keep track of state. The for loops, however, have to be changed into while for this to work:
function bubbleSort(arr) {
(function(i, j) { // <- this closes over i and j
function nextSortStep() {
while (i < arr.length) {
while (j < arr.length) {
highlight(j - 1);
highlight(j);
if (arr[j - 1] > arr[j]) {
visibleSwap(arr, j, j - 1);
}
j++;
return setTimeout(nextSortStep, 1000);
}
i++;
j = 1;
return setTimeout(nextSortStep, 1000);
}
exhibitArray(arr);
}
nextSortStep();
})(0, 1); // <- loop initialization
}
As an aside, JavaScript is not PHP, function names generally are in camelCase.
Following Lebedev's idea, I would store the "evolution of the sorting of the array" and then use setInterval() to show them.
http://jsfiddle.net/mari/EaYRZ/

Categories

Resources