Implementing shuffle images function - javascript

Im looking for some advice on how to start a shuffle image function, so I have 6 images atm in a div box and I want a function that allows them to shuffle around, how should I start?? Should I put the images in a separate div as well? any help or example code appreciated, thanks

Following is a jQuery solution. You can achieve same results using vanilla JavaScript but it will require few extra lines of code.
<div id="deck">
<div><img src="" /></div>
<div><img src="" /></div>
.
.
.
</div>
// Fisher–Yates Shuffle (Knuth variant)
// To shuffle an array a of n elements (indices 0..n-1):
// for i from n - 1 downto 1 do
// j <- random integer with 0 <= j <= i
// exchange a[j] and a[i]
// jQuery specific:
// 1) remove elements from DOM and convert them into a native JavaScript array
// 2) apply algorithm
// 3) inject the array back to DOM
var a = $("#deck > div").remove().toArray();
for (var i = a.length - 1; i >= 1; i--) {
var j = Math.floor(Math.random() * (i + 1));
var bi = a[i];
var bj = a[j];
a[i] = bj;
a[j] = bi;
}
$("#deck").append(a);
Demo here

I've implemented something like this for a memory card game, so you can probably get some hints from that. Just do a resources search for 'shuffle' in my .js files and you should get an idea how I've done it. From memory, I originally put all my images in a div, then move them around with the shuffle function. I think later on I started shuffling an array of URLs instead then generating the image elements later.
I used Ca-Phun Ung's 'Shuffle' JQuery plugin (although I think I re-wrote my own version to better understand its inner workings). You may find some useful information with that as well. See JQuery Shuffle

Ok, I got this!
var divs = $('selector to get all divs'); // This could be $('img');
function shuffle(divs, iterations) {
var size = divs.size();
for(var i = iterations; i > 0; i--) {
// Pick two divs at random
var div1 = divs[Math.floor(Math.random() * size)],
div2 = divs[Math.floor(Math.random() * size)];
// Ensure they are different divs
if(div1.is(div2)) {
continue;
}
// Swap the two divs
div1.clone().insertAfter(div2);
div2.detach().insertAfter(div1);
div1.detach();
}
};
shuffle(divs, 1000);
Although this will probably be better if you put a divs.hide(), then divs.show() so that you don't see the thrashing. However, maybe that is what you want? May you want a delay in there and use jQuery's animate function to make it fancy. This particular solution requires that the img's position in the DOM determines the location. A more complex solution would be to swap the css position during the loop.
var savedLeft = div1.css("left"),
savedTop = div1.css("top");
div1.css("left", div2.css("left"));
div1.css("top", div2.css("top"));
div2.css("left", savedLeft);
div2.css("top", savedTop);
I haven't actually TRIED this yet, but it looks right from here :P

Related

How can you dynamically slice an array in Javascript/jQuery?

I have a photo gallery that includes images that will be continuously uploaded. The PHP array has been converted/encoded to a JSON array so that I can manipulate the data with JavaScript.
Ideally, I would like to click a button ("Next Set" in the CodePen example) and load the next set (of 2) thumbnail images. This is in an effort to not load all of the images at once, which could be hundreds.
Problem: I cannot figure out how to dynamically slice the array on click (next 5 images). I can of course load, say, 2 at a time:
myArray.slice(0,2);
myArray.slice(3,5);
However, this will not work because images will be continuously added to the gallery. Furthermore, I would have to have too many sets of the above to keep slicing 5 out at a time.
I have tried:
Splitting the array into smaller arrays
for loops and $.each loops
I essentially need to be able to move the start and end index of the slice by (for example) 2 on click. Right now it just keeps slicing the same two images because the slicing is not dynamic.
Here is my CodePen
I don't think there's a way to do exactly what you want, but you can just keep track of where you were in the array and do a slice from there, like this:
var nextSet = myArray.slice(lastIndex, lastIndex + 2);
Replace your existing click() with this (including the declaration of lastIndex) to try it:
var lastIndex = 0
$('.button').click(function() {
var nextSet = myArray.slice(lastIndex, lastIndex + 2);
lastIndex += 2;
for (var i = 0; i < 2; i++) {
var li = $('<li/>').attr('role', 'menuitem').appendTo('.myList').append('<img src=' + nextSet[i] + '>');
}
});
Note that I've moved the slice() line outside the for loop. There's no need to slice a new array for every iteration.
Here's a CodePen using .slice().
An alternate method is to use to shift() to peel off the first item in the array with each iteration:
var nextItem = myArray.shift()
This is destructive though (it removes the item from the original array), so you'll need to make a copy of the original array first if you want to use it for anything else. Replace your click() with:
$('.button').click(function() {
for (var i = 0; i < 2; i++) {
var nextItem = myArray.shift();
var li = $('<li/>').attr('role', 'menuitem').appendTo('.myList').append('<img src=' + nextItem + '>');
}
});
Here's a CodePen using .shift().
your problem is simple i think. you do a slice and allways get back the same array
var array = [0,1,2,3,4,5];
let newArray1 = array.slice(0,2); // returns a new array
let newArray2 = array.slice(0,2); // returns the same new array
for(var i = 0; i < 2; i = i+2) {
result = array.slice(i, i+2);
console.log(result);
}

Javascript performance array of objects preassignment vs direct use

I have a doubt about how can be affected to speed the use of object data arrays, that is, use it directly or preasign them to simple vars.
I have an array of elements, for example 1000 elements.
Every array item is an object with 10 properties (for example).
And finally I use some of this properties to do 10 calculations.
So I have APPROACH1
var nn = myarray.lenght;
var a1,a2,a3,a4 ... a10;
var cal1,cal2,.. cal10
for (var x=0;x<nn;x++)
{ // assignment
a1=my_array[x].data1;
..
a10 =my_array[x].data10;
// calculations
cal1 = a1*a10 +a2*Math.abs(a3);
...
cal10 = (a8-a7)*4 +Math.sqrt(a9);
}
And APPROACH2
var nn = myarray.lenght;
for (var x=0;x<nn;x++)
{
// calculations
cal1 = my_array[x].data1*my_array[x].data10 +my_array[x].data2*Math.abs(my_array[x].data3);
...
cal10 = (my_array[x].data8-my_array[x].data7)*4 +Math.sqrt(my_array[x].data9);
}
Assign a1 ... a10 values from my_array and then make calculations is faster than make the calculations using my_array[x].properties; or the right is the opposite ?????
I dont know how works the 'js compiler' ....
The kind of short answer is: it depends on your javascript engine, there is no right and wrong here, only "this has worked in the past" and "this don't seem to speed thing up no more".
<tl;dr> If i would not run a jsperf test, i would go with "Cached example" 1 example down: </tl;dr>
A general rule of thumb is(read: was) that if you are going to use an element in an array more then once, it could be faster to cache it in a local variable, and if you were gonna use a property on an object more then once it should also be cached.
Example:
You have this code:
// Data generation (not discussed here)
function GetLotsOfItems() {
var ret = [];
for (var i = 0; i < 1000; i++) {
ret[i] = { calc1: i * 4, calc2: i * 10, calc3: i / 5 };
}
return ret;
}
// Your calculation loop
var myArray = GetLotsOfItems();
for (var i = 0; i < myArray.length; i++) {
var someResult = myArray[i].calc1 + myArray[i].calc2 + myArray[i].calc3;
}
Depending on your browser (read:this REALLY depends on your browser/its javascript engine) you could make this faster in a number of different ways.
You could for example cache the element being used in the calculation loop
Cached example:
// Your cached calculation loop
var myArray = GetLotsOfItems();
var element;
var arrayLen = myArray.length;
for (var i = 0; i < arrayLen ; i++) {
element = myArray[i];
var someResult = element.calc1 + element.calc2 + element.calc3;
}
You could also take this a step further and run it like this:
var myArray = GetLotsOfItems();
var element;
for (var i = myArray.length; i--;) { // Start at last element, travel backwards to the start
element = myArray[i];
var someResult = element.calc1 + element.calc2 + element.calc3;
}
What you do here is you start at the last element, then you use the condition block to see if i > 0, then AFTER that you lower it by one (allowing the loop to run with i==0 (while --i would run from 1000 -> 1), however in modern code this is usually slower because you will read an array backwards, and reading an array in the correct order usually allow for either run-time or compile-time optimization (which is automatic, mind you, so you don't need to do anything for this work), but depending on your javascript engine this might not be applicable, and the backwards going loop could be faster..
However this will, by my experience, run slower in chrome then the second "kinda-optimized" version (i have not tested this in jsperf, but in an CSP solver i wrote 2 years ago i ended caching array elements, but not properties, and i ran my loops from 0 to length.
You should (in most cases) write your code in a way that makes it easy to read and maintain, caching array elements is in my opinion as easy to read (if not easier) then non-cached elements, and they might be faster (they are, at least, not slower), and they are quicker to write if you use an IDE with autocomplete for javascript :P

Non repeating array number (which is added twice or more with Jquery

I know the question about obtaining a random number with javascript (non repeating) is often asked but in my case I append the same jquery code twice or three time and I would like to obtain different information each time.
First i have a large array (150 items) which is built this way :
var arr = [
{
"Numéro": "1",
"Chinois": "爱",
"Pinyin": "ài",
"Français": "aimer, affection, apprécier",
"Classificateurs": ""
},
Then I found on another post this random function :
while(arr.length < 150){
var randomnumber=Math.ceil(Math.random()*147)
var found=false;
for(var i=0;i<arr.length;i++){
if(arr[i]==randomnumber){found=true;break}
}
if(!found)arr[arr.length]=randomnumber;
}
Then I append the array information (I tried randomly - It's a flashcard kind of page so on click, the next "index" should be randomized and unique) on the page :
$('#qcm-az, .suivantQcm1').on ('click', function(qcmaz){
$('#reponse1').html(arr[index].Français);
$('#reponse2').html(arr[147 -Math.floor((Math.random() * 23)+1)].Français);
$('#reponse3').html(arr[99 - Math.floor((Math.random() * 65)+1)].Français);
$('#reponse4').html(arr[43 - Math.floor((Math.random() * 21)+1)].Français);
index = randomnumber;
});
So basically on page load or (if the next arrow is clicked) I would like the "index = randomnumber" to be ran once again but it seems stuck (because the random number seems allocated once and for all).
Finally you can see that, on my different divs, I'm using a not so random function to get a different index number. I often encounter a problem which is that the "good answer" (reponse1) is the same as in one of the "wrong answer" (reponse2,3 or 4).
I hope I explained myself clearly - I'm beginning in Javascript/Jquery. Thank you in advance.
Edit : I added a fiddle to show you the problem (just click on the body to move to next item - which is stuck after one click here)
http://jsfiddle.net/Hv8SD/
You array-shuffling algorithm is fully incorrect.
A can propose this variant:
var counter = 0, newArray = [];
while(counter < 147)
{
var randomnumber=Math.ceil(Math.random()*147 - 1)
if(!newArray[randomnumber]) // if newArray doesn't contains index `randomnumber`
{
newArray[randomnumber]=arr[counter];
counter++;
};
};
JSFiddle DEMO

Fast way to append large list to dom

I am trying to populate an empty list using an array of photo names. I have made this work already, but with a large amount of photos it can become relatively slow. More than 500 photos is not unusual.
I am wondering if someone could find a way to make this code work faster, or tell me what make this code run slow so I can have another look at it myself.
The code I have is as follows. this.photoListElement is a jQuery object referring to the unordered list element. photoNames is an array of photo name strings. Variables are declared at the top of the function which is not shown here. isThumbDownloaded checks a variable in an object. getThumb and getThumbId are functions which add some strings together.
(...)
place = [];
for(i=0; i< photoNames.length; ++i) {
photoName = photoNames[i];
if(coverages.isThumbDownloaded(coverageId, photoName)){ // A function which checks if a photo is downloaded. If it is, the photo should not be hidden, and the right background should be applied.
bg = 'background-image:url(\''+coverages.getThumb(coverageId, photoName) + '?' + new Date().getTime()+'\');';
cls = '';
} else {
bg = '';
cls = 'hidden';
}
place[i] = '<div id="'+ this.getThumbId(photoName) +'" photoName="'+photoName+'" style="'+bg+'" class="phoPhoto '+cls+'" onclick="$.mobile.changePage($(\'#carousel\'), {transition: \'slidefade\'})"></div>';
}
this.photoListElement.html(place.join(''));
(...)
Help is very much appreciated.
After research
The problem is not the loop, although some minor optimizations can be done, but the the dom insertion.
In the loop you are counting the number of photoNames on each iteration:
for(i=0; i< photoNames.length; ++i)
Keep the length in a variable instead and the loop will be faster:
for (var i = 0, ilen = photoNames.length; i < ilen; i += 1)
Also, string concatenation might be faster than array join, check this jsperf .
So:
place = "";
...
place += '<div>.......';
..
this.photoListElement.html(place);
Try using
$('ul').append(ilen);

how to fadein LI elements randomly? (jquery)

Hi I've got a set of <li> with a hover effect, what I want is when the page loads ALL the <li> elements fade-in randomly.
I don't want to shuffle them...they should keep their ordering intact meaning 1,2,3,4,5. I just want to make them appear on the page randomly and stay there.
Test page:
http://humayunrehman.com/hovertest/
You can do something like this:
var v = $("#blocks > li").css('visibility', 'hidden'), cur = 0;
for(var j, x, i = v.length; i; j = parseInt(Math.random() * i), x = v[--i], v[i] = v[j], v[j] = x);
function fadeInNextLI() {
v.eq(cur++).css('visibility','visible').hide().fadeIn();
if(cur != v.length) setTimeout(fadeInNextLI, 50);
}
fadeInNextLI();
You can view a demo with your html/images here. Credit to Jordan Boesch for the sorting algorithm, the same one used in jsquares.
This will hide them all, grab at random a next :hidden one, fade it in, and 50ms later start the next one, creating a random-ish fadeIn effect. Just adjust the time as needed, also pass a time into .fadeIn() if you want. This will stop queuing effects when it's done as well.

Categories

Resources