How to cycle between two arrays - javascript

I'm trying to create a cycling sliding animation for set of elements, i have two arrays:
var elms = [elm1, elm2, elm3];
var props = [{x,y,width,height,z-index,opacite,....}, {....}, {....}];
on initializing, elms will be positioned in the same order as props: "-> is not part of the syntax it's just to make things easier to explain and it means 'do something with'"
elms[0] -> props[0];
emls[1] -> props[1];
elms[2] -> props[2];
but then i want to cycle them like:
elms[0] -> props[2]
elms[1] -> props[0]
elms[2] -> props[1]
and then:
elms[0] -> props[1]
elms[1] -> props[2]
elms[2] -> props[0]
and so forth...
i tried this:
function index(n, array){
var m = n;
if(n > array.length){
m = n - array.lenth;
}else if(n < 0){
m = array.length + n;
}
return m;
}
var active = 0; //the front element
function slide(direction){
for (i=0; i< elms.length; i++)
{
elms[i] -> props[index(i - active, props)]
}
if(direction == 'fw'){
if(active++ => elms.length){
active = 0;
}else{
active++;
}
}else if(direction == 'bw'){
if(active-- < 0){
active += elms.length;
}else{
active--;
}
}
}
setInterval(function(){slide('fw')}, 3000);
now the above code works fine, but i'm sure this has been done many times before and i'm wondering does anyone know if there is a better less complicated way to do this which allows to loop forward and backward?

If you don't mind modifying the props array, you can just .shift() off the first element and then .push() is onto the end of the array and then once again do:
elms[0] -> props[0];
emls[1] -> props[1];
elms[2] -> props[2];
To rotate the props array, you could just do this:
function rotateProps() {
var front = props.shift();
props.push(front);
}
So, each cycle just call rotateProps() and then repeat what you did the first time.

How about using module? Have a global var that you increment each time you shift, then module that with the length of the arrays. You could access the arrays like: props[shift%len]
If len is 3 (as above), you could get these results if you are accessing the props in relation to the first elmsIdx (0):
POC: jsfiddle.net/Q8dBb, also this would work without modifying your arrays so I believe it would be faster
shift = 0; // (shift+elmsIdx)%len == 0;
shift = 1; // (shift+elmsIdx)%len == 1;
shift = 2; // (shift+elmsIdx)%len == 2;
shift = 3; // (shift+elmsIdx)%len == 0;
shift = 4; // (shift+elmsIdx)%len == 1;
etc
Actually, using an object could make it more flexible (shifting multiple ways, resetting, whatever you want to add). Here is an example for that:
function Shift(len) {
var _len = len;
var _s = 0;
this.left = function() {
_s = (_s + 1)% _len;
}
this.right = function() {
_s = (_s - 1);
if (_s < 0) {
_s = _s + _len;
}
}
this.get = function(idx) {
return (_s + idx)% _len;
}
this.reset = function() {
_s = 0;
}
}
in use: http://jsfiddle.net/6tSup/1/

Related

javascript multiple AND conditions in IF statement inside for loop javascript

I feel stupid because I´m stuck with a basic. I have three set of classes that contains paragraphs and I want to change the background color of each one depending on day (with New Dat.getDay().
I dont know how to mix for loop and if statements for each set of classes correctly. I guess it´s something simple but I missing it!
function changecolor() {
var d = new Date();
var n = d.getDay();
var weekda = document.getElementsByClassName('weekdays');
var sat = document.getElementsByClassName('saturday');
var dom = document.getElementsByClassName('sun-fer');
for (var i = 0; i < weekda.length && i < sat.length && i < dom.length; i++)
if (n > 0 || n < 6) {
weekda[i].setAttribute("style", "background-color:#0091ea;color:white;");
}
else if (n == 6) {
sat[i].setAttribute("style", "background-color:#0091ea;color:white;");
} else {
dom[i].setAttribute("style", "background-color:#0091ea;color:white;");
}
}
}
changecolor();
You need to group conditions. Read more about Operator precedence
for (var i = 0;( (i < weekda.length) && (i < sat.length) && (i < dom.length)); i++){
// your code
}
Part of the problem may be you have background-color:#0091ea;color:white; for all three options. Therefore you may not be seeing any change.
Personally I would break this up a little to make it more flexible and a little easier to read (and maintain). For example:
function changecolor() {
var d = new Date();
var e = null;
var s = null;
switch(d.getDay()) {
case 6:
e = document.getElementsByClassName('saturday');
s = "background-color:#0091ea;color:white;";
break;
case 0:
e = document.getElementsByClassName('sun-fer');
s = "background-color:#0091ea;color:green;";
break;
default:
e = document.getElementsByClassName('weekdays');
s = "background-color:#0091ea;color:blue;";
}
// now update the color
updateItem(e,s);
}
function updateItem(e,s) {
var i, max = e.length;
for(i=0;i<max;i++) {
e[i].setAttribute("style",s);
}
}

What is the name of this Sort Algorithm?

var counter = 0;
function sort(arr)
{
var totalItem = arr.length;
var temp ;
var index;
var isSortDone = true;
for( index = 0 ; index < totalItem ; index ++)
{
if(arr[index] > arr[index+1])
{
temp = arr[index];
arr[index] = arr[index+1];
arr[index+1] = temp ;
isSortDone = false;
}
if(arr[totalItem-(1+index)] < arr[totalItem-(2+index)] )
{
temp = arr[totalItem-(1+index)]
arr[totalItem-(1+index)] = arr[totalItem-(2+index)]
arr[totalItem-(2+index)] = temp
isSortDone = false;
}
counter++;
}
if(isSortDone == true) { console.log(counter + ":Sort is Done", arr); return 0;}
return sort(arr);
}
Looks like a recursive bi-directional version of bubblesort (https://en.wikipedia.org/wiki/Bubble_sort) similar to this variant: https://en.wikipedia.org/wiki/Cocktail_shaker_sort, but with both loops rolled into one (which doesn't make much of a difference wrt. performance or other characteristics).
Note that each recursive call could omit the first and last item, as they will be the smallest / biggest globally (you could implement this by adding an offset parameter).
Given that there may be up to n recursive calls, this is probably likely to cause a stack overflow.

Why is my code executing far more times than it's supposed to?

I'm currently working on a poker odds generator and it's pretty much done, except for one thing. The program runs far more often than it should. I know that this is coming from the compare() function, because when I add a variable Q to keep track of the number of times the main function playPoker() has run, it produces a huge number until I comment it out - at which point it returns the exact number I'd expect.
Can any of you point out where I'm going wrong with this. I can't see why one function should lead to Q being incremented so much more than it should be. Literally, the last time I ran it the number was (32,487 instead of 100). I present the code below (without the poker hand-checking functions because they're not really important). Why is playPoker() running so many times?!
var Q = 0;
function playPoker(tableSize) {
//Create the players, the deck and the card table which stores the 5 cards the players have in common
var players = createPlayers(tableSize);
var deck = createDeck();
var cardTable = new CardTable();
//Deal each player two cards
for (i = 0; i < 2; i++) {
for (j = 0; j < players.length; j++) {
deal(deck, players[j]);
}
}
//Put five cards down on the table
for (k = 0; k < 5; k++) {
deal(deck, cardTable);
}
//Check for various winning hands here for each player
for (m = 0; m < players.length; m++) {
//Merge the player's two cards with the five cards on the table
var subjectCards = (players[m].cards).concat(cardTable.cards);
//Make an array of the values of each of the seven cards, which will be used to determine 4 of a kind, 3 of a kind and pairs
var valuesInOrder = getValuesInOrder(subjectCards);
//Create a dummy array, so that valuesInOrder remains unchanged
var straightValues = valuesInOrder.slice();
//Remove any duplicate card, meaning that the array contains only unique values (i.e. 2, 4, 5, 7, K ... NOT 2, 2, 2, 8, K, K, A)
var straightValues = straightenUp(straightValues);
//Calculate how many pairs are in the hand
var numPairs = howManyPairs(valuesInOrder, straightValues, players[m]);
//Find out whether the 5 table cards contain three cards of the same suit. If not, then a flush is impossible.
var flushPotential = threeSameSuit(cardTable.cards);
//Find out which hand each player has (i.e. straight, 3OAK, pair)
checkPokerHand(subjectCards, straightValues, valuesInOrder, flushPotential, numPairs, players[m])
}
var rankedPlayers = compare(players);
//return players;
Q++;
return Q;
}
And here's the for-loop that sets it off.
for (z = 0; z < 100; z++;) {
playPoker(4);
}
And here's the compare() function:
function compare(players) {
var remPlayers = players.slice();
var rankings = [];
var potentialWinners = [];
//Collect all the players' rankings in an array
for (i = 0; i < remPlayers.length; i++) {
rankings.push(remPlayers[i].rank);
}
//Find the highest ranking
var highestRank = getHighestValue(rankings);
//Move any players with the highest ranking to an array for potential winners
for (j = 0; j < remPlayers.length; j++) {
if (remPlayers[j].rank == highestRank) {
potentialWinners.push(remPlayers[j]);
remPlayers.splice(j, 1);
j--;
}
}
//With all potential winners gone, mark all other players with an L for losing.
for (k = 0; k < remPlayers.length; k++) {
remPlayers[k].result = 'L'
}
var foundWinner = false;
if (potentialWinners.length < 2) {
potentialWinners[0].result = 'W';
foundWinner = true;
}
//Check there is more than one potential winner. If not, the only guy in the array has won.
if (!foundWinner) {
//Loop through all players first cards and find the highest value, then delete any who don't have that, marking them with 'L'.
//If there is no single remnant, do the same for second cards, then third, then fourth, etc.
for (p = 0; p < 5; p++) {
var subRankings = [];
for (q = 0; q < potentialWinners.length; q++) {
subRankings.push(potentialWinners[q].bestHand[p]);
}
var highestSubRanking = getHighestValue(subRankings);
//Mark 'L' and remove any player who does not meet the highest subranking
for (m = 0; m < potentialWinners.length; m++) {
if (potentialWinners[m].bestHand[p] < highestSubRanking) {
potentialWinners[m].result = 'L';
potentialWinners.splice(m, 1);
}
if (potentialWinners.length < 2) {
potentialWinners[0].result = 'W';
//Set this flag to true to break the loop because a winner has been found
foundWinner = true;
break;
}
}
//Break the loop if we have found a winner
if (foundWinner) {
break;
}
//If we still haven't found a winner by the end of the 5th loop, all remaining players draw
if (p == 4) {
for (z = 0; z < potentialWinners.length; z++) {
potentialWinners[z].result = 'D';
}
}
if (foundWinner) {
break;
}
}
}
return players;
}
Try using var declarations on your variables to manage their scope within their relevant functions?

jquery/javascript -how to loop through array and create variables in each iteration?

I'm wondering for some time now why this fails:
if (longest.length >= 3) {
for ( var i = 0; i < longest.length-1; i++) {
var $last[i] = longest[i].splice(-1).toString();
//if ( $( $last[i] ).closest(':jqmData(role="panel")') == "popover" ) {
//var gotoPage = $last[i];
// }
}
}
longest is an array, which contains array elements.
I want to loop through the number of arrays in longest and create variables from each nested arrays' last element. The .splice(-1).toString() fails telling me "missing ; before statement"
What am I doing wrong?
EDIT:
longest will look something like this:
[[#menu, #menuSub1, #menuSub2], [#main, yield, yield], [#pop1, #pop1-1, #pop1-2]]
It's within a function to track the browser-history in a mobile-app with different panels.
EDIT2:
Finished code (Thx Mic):
if (longest.length >= 3) {
var $last = [];
for ( var i = 0; i < longest.length; i++) {
$last.push( longest[i][ longest[i].length - 1 ]);
if ( $( $last[i] ).closest(':jqmData(role="panel")').jqmData('panel') == "popover" ) {
var gotoPage = $last[i]; }
}
}
You should write something like:
if (longest.length >= 3) {
var $last = [];
for ( var i = 0; i < longest.length-1; i++) {
$last.push( longest[i][ longest[i].length - 1 ] );
}
}
and get the values with $last[0]
Or use a hash like:
if (longest.length >= 3) {
var hash = {};
for ( var i = 0; i < longest.length-1; i++) {
hash['$last'+ i] = longest[i][ longest[i].length - 1 ];
}
}
and get the content using for instance hash.$last0

Ordering z-indexes in an array

I have an array which looks something along the lines of
resourceData[0][0] = "pic1.jpg";
resourceData[0][1] = 5;
resourceData[1][0] = "pic2.jpg";
resourceData[1][1] = 2;
resourceData[2][0] = "pic3.jpg";
resourceData[2][1] = 900;
resourceData[3][0] = "pic4.jpg";
resourceData[3][1] = 1;
The numeric represents the z-index of the image. Minimum z-index value is 1. Maximum (not really important) is 2000.
I have all the rendering and setting z-indexes done fine. My question is, I want to have four functions:
// Brings image to z front
function bringToFront(resourceIndex) {
// Set z-index to max + 1
resourceData[resourceIndex][1] = getBiggestZindex() + 1;
// Change CSS property of image to bring to front
$('#imgD' + resourceIndex).css("z-index", resourceData[resourceIndex][1]);
}
function bringUpOne(resourceIndex) {
}
function bringDownOne(resourceIndex) {
}
// Send to back z
function sendToBack(resourceIndex) {
}
So given then index [3] (900 z):
If we send it to the back, it will take the value 1, and [3] will have to go to 2, but that conflicts with [1] who has a 2 z-index so they need to go to three etc.
Is there an easy programatical way of doing this because as soon as I start doing this it's going to get messy.
It's important that the indexes of the array don't change. We can't sort the array unfortunately due to design.
Update
Thanks for answers, I'll post the functions here once they are written incase anyone comes across this in the future (note this code has zindex listed in [6])
// Send to back z
function sendToBack(resourceIndex) {
resourceData[resourceIndex][6] = 1;
$('#imgD' + resourceIndex).css("z-index", 1);
for (i = 0; i < resourceData.length; i++) {
if (i != resourceIndex) {
resourceData[i][6]++;
$('#imgD' + i).css("z-index", resourceData[i][6]);
}
}
}
Loops! This function will reorder affected images around it. It will work with images that have widely separated z-index values. It also does not perform any changes unless it needs to.
EDIT: added function to do the CSS work
EDIT 2: Corrected problem with top/bottom functions - it wasn't moving all the images affected, now it is.
var resourceData = Array();
resourceData[0] = Array();
resourceData[0][0] = "pic1.jpg";
resourceData[0][1] = 5;
resourceData[1] = Array();
resourceData[1][0] = "pic2.jpg";
resourceData[1][1] = 2;
resourceData[2] = Array();
resourceData[2][0] = "pic3.jpg";
resourceData[2][1] = 900;
resourceData[3] = Array();
resourceData[3][0] = "pic4.jpg";
resourceData[3][1] = 1;
function _doMoveImage(ptr) {
// Change CSS property of image
$('#imgD' + ptr).css("z-index", resourceData[ptr][1]);
}
// Brings image to z front
function bringToFront(resourceIndex) {
var highest_idx = 0;
for (var i = 0; i < resourceData.length; i++) {
// for all images except the target
if (i != resourceIndex) {
// preserve the highest index we encounter
if (highest_idx < resourceData[i][1])
highest_idx = resourceData[i][1];
// move any images higher than the target down by one
if (resourceData[i][1] > resourceData[resourceIndex][1]) {
resourceData[i][1]--;
_doMoveImage(i);
}
}
}
// now move the target to the highest spot, only if needed
if (resourceData[resourceIndex][1] < highest_idx) {
resourceData[resourceIndex][1] = highest_idx;
_doMoveImage(resourceIndex);
}
return;
}
function bringUpOne(resourceIndex) {
var next_idx = 2000;
var next_ptr = false;
for (var i =0; i < resourceData.length; i++) {
// for all images except the target
if (
i != resourceIndex &&
next_idx > resourceData[i][1] &&
resourceData[i][1] > resourceData[resourceIndex][1]
){
next_idx = resourceData[i][1];
next_ptr = i;
}
}
// only move if needed
if (next_ptr) {
// target takes next's index
resourceData[resourceIndex][1] = resourceData[next_ptr][1];
// next's index decreases by one
resourceData[next_ptr][1]--;
_doMoveImage(resourceIndex);
_doMoveImage(next_ptr);
}
return;
}
function bringDownOne(resourceIndex) {
var next_idx = 0;
var next_ptr = false;
for (var i =0; i < resourceData.length; i++) {
// for all images except the target
if (
i != resourceIndex &&
next_idx < resourceData[i][1] &&
resourceData[i][1] < resourceData[resourceIndex][1]
){
next_idx = resourceData[i][1];
next_ptr = i;
}
}
// only move if needed
if (next_ptr) {
// target takes next's index
resourceData[resourceIndex][1] = resourceData[next_ptr][1];
// next's index decreases by one
resourceData[next_ptr][1]++;
_doMoveImage(resourceIndex);
_doMoveImage(next_ptr);
}
}
// Send to back z
function sendToBack(resourceIndex) {
var lowest_idx = 2000;
for (var i = 0; i < resourceData.length; i++) {
// for all images except the target
if (i != resourceIndex) {
// preserve the lowest index we encounter
if (lowest_idx > resourceData[i][1])
lowest_idx = resourceData[i][1];
// move any images lower than the target up by one
if (resourceData[i][1] < resourceData[resourceIndex][1]) {
resourceData[i][1]++;
_doMoveImage(i);
}
}
}
// now move the target to the lowest spot, only if needed
if (resourceData[resourceIndex][1] > lowest_idx) {
resourceData[resourceIndex][1] = lowest_idx;
_doMoveImage(resourceIndex);
}
return;
}
There it is: copy your structure and have it properly ordered, or if you prefer call it indexed. When you need the picture find the proper z-index and proceed w/ the rendering.
You can do that dynamically and use heap, if you don't wish to copy the entire structure.
Not tested, but how about this. For bringUpOne, bringDownOne one you can swap the z-indexes, e.g:
function bringUpOne(resourceIndex) {
var myZIndex = resourceData[resourceIndex][1];
var nextZIndex = resourceData[resourceIndex + 1][1];
resourceData[resourceIndex][1] = nextZIndex;
resourceData[resourceIndex + 1][1] = myZindex;
}
For bringing to the front:
function bringToFront(resourceIndex) {
var maxZIndex = resourceData[maxResourceIndex][1];
resourceData[resourceIndex][1] = maxZIndex + 1;
}
Now that's all fine. But what happens if you want to successively set images to the back? You can either set the zIndex to 0 each time (don't know how many you'll have actually visiable at any time) or you can start with the lowest zIndex set to something like 2000 or 10000 or whatever, which will acccomodate many calls to setToBack.
Edit: This assumes the list is ordered by zIndex to start with.

Categories

Resources