JavaScript Variable in method modifying object's attribute? - javascript

I'm trying to create a poker game in JavaScript. I thought the function that tested flushes worked perfectly until I displayed the hand AFTER the method ran. If there is a flush, this function is supposed to show the user's full hand, and then only the flush underneath it. Instead, it shows only the flush, and then the flush again underneath it:
var $ = function (id) { return document.getElementById(id); };
var test = function() {
var deck = new POKER.Deck(); //creates deck
var hand = new POKER.Hand(); //creates hand
//----------------TEST HAND UNTIL FLUSH-----------------
while (hand.getValue() != POKER.HAND_TYPE.FLUSH) {
deck.refreshDeck(); //refresh deck with new cards
for (var i = 0; i < 7; ++i) { //populate hand
hand.addCard(deck.dealCard());
}
console.log(hand.size() + " before"); //only for debugging. Prints "7 before"
hand.testFlush();
console.log(hand.size() + " after"); //only for debugging. Result unexpected
if (hand.getValue() == POKER.HAND_TYPE.FLUSH) { //if hand has a flush
for (var j = 0; j < hand.size(); j++) { //display full hand
var img = document.createElement("img");
var card = hand.getCardAtIndex(j);
img.src = card.getImage();
$("images").appendChild(img);
}
for (var k = 0; k < 5; k++) { //display flush hand
var img2 = document.createElement("img");
var card2 = hand.getValueCardAtIndex(k);
img2.src = card2.getImage();
$("handImg").appendChild(img2);
}
break;
} else {
hand.empty();
}
}
};
window.onload = function() {
test();
};
The second console.log statement prints out "4 after" until the testFlush method detects a flush, and the final result is "5 after".
testFlush method:
POKER.Hand.prototype.testFlush = function() {
//first, sort cards by rank so that the highest flush is
//taken if there are more than five cards of the same suit
this.sortByRank();
this.sortBySuit();
var tempHand = this.cards; //modifiable version of this.cards
var NUM_OF_TESTS = 3; //only 3 loops required to test for all possible flushes
var LAST_CARD_INDEX = 4; //represents the fifth card, or index 4
var MAX_CARDS = 5; //maximum cards possible in a hand (valueCards)
for (var i = 1; i <= NUM_OF_TESTS; i++){
//check if 1st and 5th cards are the same suit
if(tempHand[0].getSuit() == tempHand[LAST_CARD_INDEX].getSuit()){
this.value = POKER.HAND_TYPE.FLUSH;
while(tempHand.length != MAX_CARDS){ //remove last card in tempHand until there are only five cards
tempHand.pop();
}
this.valueCards = tempHand;
}else{
tempHand.splice(0,1); //removes first card from the temporary hand
}
}
};
All "hand.size()" does in the test function is "return this.cards.length". So what I don't understand is how the testFlush method could be altering the object attribute "this.cards" when it only alters the temporary variable tempHand.
Hand object:
POKER.Hand = function(){
this.cards = [];
this.value; //integer that corresponds to the POKER.HAND_TYPE
this.valueCards = []; //array of the five cards that corresponds only to this.value
};
Hand.size method:
POKER.Hand.prototype.size = function() {
return this.cards.length;
};

The problem is this line:
var tempHand = this.cards; //modifiable version of this.cards
Assigning an array or object to a variable does not make a copy of it. The variable is a reference to the same array, so tempHand.pop() modifies this.cards as well. You can make a copy of an array with .slice():
var tempHand = this.cards.slice();

Related

Javascript file isn't appending to a filtered list

As the title reads, my javascript file won't append to a filtered list via a random generator function, for context it's being built in replit so perhaps its just a buggy bit of software on replits end, though I'm certain I've done something wrong and can't for the life of me figure out what. The main idea for this project is to have it randomly select an item from a list, append it to an empty list, then pass that string to an HTML textarea tag to be displayed as text.
Code in question:
var LowercaseList = ["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 NumList = ["1","2","3","4","5","6","7","8","9","0"];
var SpecialCharList = ["`","~","!","#","$","%","^","&","*","_","-","+","=","<",">","?","/"];
// Letter list ID's since I couldn't figure out how to run this using a database
var LetterIDList = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26];
// Number list ID's since I couldn't figure out how to run this using a database
var NumIDList = [1,2,3,4,5,6,7,8,9,10];
// Special character list ID's since I couldn't figure out how to run this using a database
var SpecialID = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17];
// Filtered Lists
var UpperFiltered = [];
var LowerFiltered = [];
var NumFiltered = [];
var SpecialFiltered = [];
// Global declarations of random number variables to grab values from intial lists
var UpperGenVariable;
var LowerGenVariable;
var NumGenVariable;
var SpecialGenVariable;
// Creates a basic password with 2 of each kind of character
function Basic () {
for (var i = 1; i < 2; i++) {
UppercaseGenerate();
}
for (var i = 1; i < 2; i++) {
LowercaseGenerate();
}
for (var i = 1; i < 2; i++) {
NumGenerate();
}
for (var i = 1; i < 2; i++) {
SpecialGenerate();
}
};
let passwordGen = document.getElementById("PasswordDisplay")
function UppercaseGenerate () {
var UpperFiltered = [];
UpperGenVariable = Math.random(0, LetterIDList.length);
for (var i = 0; i < LetterIDList.length - 1; i++) {
if (LetterIDList[i] == UpperGenVariable) {
appendItem(UpperFiltered, UppercaseList[i]);
}
};
console.log(UpperFiltered);
passwordGen.value = UpperFiltered
};
HTML textarea code:
<label style = "color:white;" for="PasswordDisplay">Your generated password ----></label>
<textarea readonly id="PasswordDisplay" name="PasswordDisplay" rows="10" cols="50">
Please select a password complexity setting
</textarea>
I changed how you generate the random number.
Also added the UppercaseList, added i <= 2 rather then i < 2 in the cycles so the yould really run 2 times, added += to passwordGen.value += UpperFiltered so the value would add up.
I guess that is it.
var UppercaseList = ["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 LowercaseList = ["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 NumList = ["1","2","3","4","5","6","7","8","9","0"];
var SpecialCharList = ["`","~","!","#","$","%","^","&","*","_","-","+","=","<",">","?","/"];
// Letter list ID's since I couldn't figure out how to run this using a database
var LetterIDList = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26];
// Number list ID's since I couldn't figure out how to run this using a database
var NumIDList = [1,2,3,4,5,6,7,8,9,10];
// Special character list ID's since I couldn't figure out how to run this using a database
var SpecialID = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17];
// Filtered Lists
var UpperFiltered = [];
var LowerFiltered = [];
var NumFiltered = [];
var SpecialFiltered = [];
// Global declarations of random number variables to grab values from intial lists
var UpperGenVariable;
var LowerGenVariable;
var NumGenVariable;
var SpecialGenVariable;
// Creates a basic password with 2 of each kind of character
function Basic () {
for (var i = 1; i <= 2; i++) {
UppercaseGenerate();
}
for (var i = 1; i <= 2; i++) {
LowercaseGenerate();
}
for (var i = 1; i <= 2; i++) {
NumGenerate();
}
for (var i = 1; i <= 2; i++) {
SpecialGenerate();
}
};
let passwordGen = document.getElementById("PasswordDisplay")
function UppercaseGenerate() {
var UpperFiltered = [];
UpperGenVariable = Math.floor(Math.random() * LetterIDList.length);
for (var i = 0; i < LetterIDList.length; i++) {
if (LetterIDList[i] == UpperGenVariable) {
UpperFiltered.push(UppercaseList[i]);
}
};
passwordGen.value += UpperFiltered
};

JS Class property "is undefined" even tho it appears to be defined

I'm quite new to JS and I'm trying to do a TicTacToe game with a custom size board in an attempt to learn a bit more. I first coded just a 3x3 version and started building up from there.
Right as I got past the point where I have a custom grid size entered right after loading the page and the grid rendering, I started getting the same problem when trying to click any cell to try and play a turn.
"this.game_state[clicked_cell_i] is undefined".
I have tried opening up F12 and checking if the game_state array (which is a 2d array of strings that tracks which cell is played and which isn't) but when I do everything seems normal and the array gets printed out without problem. (picture showcases printing out the game_state array in a 4x4 grid) https://i.stack.imgur.com/gV0pY.png
I would really appreciate it if somebody could explain to me what's happening or even better - help me fix it. Thanks :)
Code: https://jsfiddle.net/z8649pxL
class game {
status_display;
is_game_active;
curr_player;
game_state;
constructor() {
this.status_display = document.querySelector('.status');
this.is_game_active = true;
this.curr_player = "X";
this.game_state = matrix(rows, rows, "");
}
cell_played(clicked_cell, clicked_cell_i, clicked_cell_j){
this.game_state[clicked_cell_i][clicked_cell_j] = this.curr_player;
clicked_cell.innerHTML = this.curr_player;
if(this.curr_player === "X"){
document.getElementById((i*rows)+j).style.backgroundColor = "#ff6600";
} else if(this.curr_player === "O"){
document.getElementById((i*rows)+j).style.backgroundColor = "#33ccff";
}
}
cell_click(clicked_cellEvent){
debugger
const clicked_cell = clicked_cellEvent.target;
let clicked_cell_i = parseInt(clicked_cell.getAttribute('i'));
let clicked_cell_j = parseInt(clicked_cell.getAttribute('j'));
if(this.game_state[clicked_cell_i][clicked_cell_j] !== "" || !this.is_game_active) {
return;
}
this.cell_played(clicked_cell, clicked_cell_i, clicked_cell_j);
this.res_validation();
}
};
let ex_game = new game();
function create_grid() {
document.getElementById('hidestart').style.display = "none";
var Container = document.getElementsByClassName("grid");
Container.innerHTML = '';
rows = prompt("n?");
let i = 0, j = 0;
document.documentElement.style.setProperty("--columns-row", rows);
for (i = 0; i < rows ; i++) {
for(j = 0; j < rows; j++){
var div = document.createElement("div");
div.className = "cell";
div.id = (i*rows)+j;
div.setAttribute("cell-index", (i*rows)+j);
div.setAttribute("i", i);
div.setAttribute("j", j);
let wrapper = document.getElementsByClassName("grid");
wrapper[0].appendChild(div);
}
}
document.querySelectorAll('.cell').forEach(cell => cell.addEventListener('click', (e) => {
ex_game.cell_click(e);
e.stopPropagation();
}));
document.getElementById('hidestart').style.display = "block";
}
function matrix(rows, cols, defaultValue){
var arr = [];
// Creates all lines:
for(var i=0; i < rows; i++){
// Creates an empty line
arr.push([]);
// Adds cols to the empty line:
arr[i].push(new Array(cols));
for(var j=0; j < cols; j++){
// Initializes:
arr[i][j] = defaultValue;
}
}
return arr;
}```
When you call
new game()
the constructor is been called of that class.
And in that constructor you are calling matrix which requires the value of rows.
But initially the class do not have any value.
So the state is not getting initialized at that point of time.
That why when you use the array, it is getting undefined.
So to resolve this issue, you could just try to get the object of class game after getting the rows from user, and pass that rows in the arguments when calling the constructor of the class.
let ex_game = new game(rows);
And then using this argument call the function matrix.
Edit:
I have looked into your code.
The error is in the method called cell_played. you are using i and j which are not known to it. Please replace your code with following line. This would resolve your error.
cell_played(clicked_cell, clicked_cell_i, clicked_cell_j){
this.game_state[clicked_cell_i][clicked_cell_j] = this.curr_player;
clicked_cell.innerHTML = this.curr_player;
if(this.curr_player === "X"){
document.getElementById((clicked_cell_i*rows)+clicked_cell_j).style.backgroundColor = "#ff6600";
} else if(this.curr_player === "O"){
document.getElementById((clicked_cell_i*rows)+clicked_cell_j).style.backgroundColor = "#33ccff";
}
}
And also remove the parameter rows from constructor and just call the constructor after taking the number of rows from user.
let ex_game
function create_grid() {
/* document.getElementById('hidestart').style.display = "none" */
var Container = document.getElementsByClassName("grid");
Container.innerHTML = '';
rows = prompt("n?");
let i = 0, j = 0;
ex_game= new game().........

Script executes properly in ExtendScript Toolkit, but not Illustrator

I've written a script that takes a selection of multiple paths, duplicates them, and applies "Object > Envelope distort > Make with top object" on each duplicate of the bottom path with every other path in the selection using an action (don't believe there's anything in the DOM for interacting with envelopes directly). So I start with this:
https://i.stack.imgur.com/cBKZs.png
It works perfectly in ExtendScript Toolkit, giving me this:
https://i.stack.imgur.com/dLdRz.png
But if I execute the script from within Illustrator, I get this mess:
https://i.stack.imgur.com/caL0u.png
Here's my code:
var doc = app.activeDocument;
var sel = app.activeDocument.selection;
var currentLayer = app.activeDocument.activeLayer;
function envelope(){
var arr = [];
var bottomObject = sel[sel.length - 1];
bottomObject.selected = false;
for (i = 0; i < sel.length - 1; i++){
arr.push(sel[i]);
var newObjs = sel[i].duplicate();
newObjs.zOrder(ZOrderMethod.SENDBACKWARD)
}
currentLayer.hasSelectedArtwork = false;
for (i = 0; i < arr.length; i++){
var objectsToDistribute = bottomObject.duplicate();
objectsToDistribute.zOrder(ZOrderMethod.SENDTOBACK);
arr[i].selected = true;
objectsToDistribute.selected = true;
app.doScript('Envelope all', 'scriptTest');
}
}
envelope();
Here's the action set. So why would I be getting different results from the same script? Is there a way to work around this from within Illustrator?
You have to move the line currentLayer.hasSelectedArtwork = false; into the loop. It's need to clear the selection for every iteration:
...
for (i = 0; i < arr.length; i++){
currentLayer.hasSelectedArtwork = false; // <------------- here
var objectsToDistribute = bottomObject.duplicate();
objectsToDistribute.zOrder(ZOrderMethod.SENDTOBACK);
arr[i].selected = true;
objectsToDistribute.selected = true;
app.doScript('Envelope all', 'scriptTest');
}
...
And actually you don't need the action set.
It can be done via app.executeMenuCommand('Make Envelope');
Here is my version of the script:
var sel = app.activeDocument.selection; // all the objects that have been selected
var lowest = sel[sel.length-1]; // the lowest object
for (var i=0; i<sel.length-1; i++) {
var top = sel[i].duplicate(); // make a copy of the next object
var btm = lowest.duplicate(); // make a copy of the lowest object
app.selection = null; // deselect all
top.selected = true; // select the top copy
btm.selected = true; // select the bottom copy
app.executeMenuCommand('Make Envelope'); // make Envenlope
}
The only difference: it transforms the lowest object among the selected objects.

Javascript multitimensional array access not working

I am trying to enable a client to edit JS sources and define multi-dimensional arrays in this format:
imageArray[0][0][0][0] = 'image000.jpg';
imageArray[0][0][0][1] = 'image0001.jpg';
...
imageArray[1][0][0][0] = 'image1000.jpg';
imageArray[1][0][0][1] = 'image1001.jpg';
I made some dynamic matrices so JS does not output errors due to non-initialized arrays and now the client can define the arrays.
The problem is when I try to print some images, for some arrays (sub-arrays) there is a problem.
If you check check this attached document: https://dl.dropboxusercontent.com/u/58889914/tmp/bt4-forum.html you will see that it prints the wrong image in alert()
Do you have idea what the problem is ?
Thanks a lot in advance.
Attachment content:
<script type="text/javascript">
/// CONFIG ////
function initArray(maxRows, maxCols)
{
var imageArray = [];
for( c= 0; c < maxRows; c++){
imageArray.push(recurGenCol(1, maxRows, maxCols));
}
return imageArray;
}
function recurGenCol(col, maxRows, maxCols)
{
if(col >= maxCols){
return "";
}
var row_col = [];
row_col = recurGenCol(col+1, maxRows, maxCols);
var row_row = [];
for(k = 0; k < maxRows; k++)
{
row_row.push(row_col);
}
return row_row;
}
// INIT:
var rows = 10;
var cols = 5;
var imageArray = initArray(rows, cols);
//console.log(imageArray);
// END CONFIG. Start definng array //
//var imageArray = imageArraya;
imageArray[0][0][0][0] = 'image_0_0_0_0.jpg';
imageArray[0][0][0][1] = 'image_0_0_0_1.jpg';
imageArray[0][0][0][2] = 'image_0_0_0_2.jpg';
//console.log( imageArray[0][0][0][1]);
imageArray[0][0][0][3] = 'image_0_0_0_3.jpg';
imageArray[0][0][0][4] = 'image_0_0_0_4.jpg';
imageArray[0][0][1][0] = 'image_0_0_1_0.jpg';
imageArray[0][0][1][1] = 'image_0_0_1_1.jpg';
imageArray[0][0][1][2] = 'image_0_0_1_2.jpg';
imageArray[0][0][1][3] = 'image_0_0_1_3.jpg';
imageArray[0][0][2][0] = 'image_0_0_2_0.jpg';
imageArray[0][0][2][1] = 'image_0_0_2_1.jpg';
imageArray[0][0][2][2] = 'image_0_0_2_2.jpg';
imageArray[0][0][3][3] = 'image_0_0_2_3.jpg';
imageArray[0][0][3][0] = 'image_0_0_3_0.jpg';
imageArray[0][0][3][1] = 'image_0_0_3_1.jpg';
imageArray[0][0][3][2] = 'image_0_0_3_2.jpg';
imageArray[0][0][3][3] = 'image_0_0_3_3.jpg';
imageArray[0][1][0][0] = 'image_0_1_0_0.jpg';
imageArray[0][2][0][0] = 'image_0_2_0_0.jpg';
imageArray[0][3][0][0] = 'image_0_3_0_0.jpg';
imageArray[0][3][0][1] = 'image_0_3_0_1.jpg';
imageArray[0][3][0][2] = 'image_0_3_0_2.jpg';
imageArray[0][3][0][3] = 'image_0_3_0_3.jpg';
imageArray[1][0][0][0] = 'image_1_0_0_0.jpg';
imageArray[1][0][0][1] = 'Image_1_0_0_1.jpg';
imageArray[1][0][0][2] = 'image_1_0_0_2.jpg';
imageArray[2][0][0][0] = 'image_2_0_0_0.jpg';
imageArray[2][0][0][1] = 'image_2_0_0_1.jpg';
imageArray[2][0][0][2] = 'image_2_0_0_2.jpg';
imageArray[2][0][0][3] = 'image_2_0_0_3.jpg';
imageArray[2][1][0][0] = 'image_2_1_0_0.jpg';
imageArray[2][1][0][1] = 'image_2_1_0_1.jpg';
//imageArray[6][1][0][1] = 'image_2_1_0_1.jpg';
var img =imageArray[0][0][1][0];
//console.log(log);
alert(img);
</script>
SOLUTION
This took me some time ... but I enjoyed every second!
function initArray(maxRows, maxCols){
var c = -1, farray = [];
var recursive = function(array){
c++;
for(var r = 0; r < maxRows; r++){
if(c == maxCols) array[r] = '';
else array[r] = recursive([]);
}
c--;
return array;
};
return recursive(farray);
}
I support Rafael's solution. But I wanted to make it clear why the original code doesn't work as expected.
In many programming languages, you can have multiple places in memory point to the same location. Typically this is done with named variables. So here's a simple example...
a = b = c = {hello: "there"};
// now a.hello would mean "there",
// so would b.hello and c.hello
c.hello = "bye";
// now, even a.hello would mean "bye";
But it doesn't have to be done like this and array indexes can actually behave the same way.
So observe how I have commented your code and added new console logs. What you see is that, in a lot of cases, you are pushing the same object to multiple places. When you do that, changing its value in one place changes it everywhere, because they're just references to the same thing.
function initArray () {
// This is the first point any array ever actually exists...
var funArray = [];
console.log('Just created the funArray.');
for (i= 0; i < 10; i++){
// Does ten pushes to the funArray with whatever
// recurGenCol returns...
funArray.push(recurGenCol(1, 10, 5));
console.log('Just pushed a single multi-level array to the funArray. None of these reference the same object.');
}
// Returns the funArray after those ten pushes...
return funArray;
}
function recurGenCol(col, maxRows, maxCols){
var i;
// Here, col starts at 1 on the first iteration,
// it then reaches 5 on the fifth iteration,
// passing the if check, and the function returns
// to initArray() with an empty string.
console.log('About to check if col ('+col+') is greater than or equal to 5.');
if (col >= 5){
console.log('It was true! Returning to '+arguments.callee.caller.name+' with an empty string.');
return "";
}
var row_col = [];
//console.log('Just created row_col, brand new, from scratch.');
row_col = recurGenCol(col+1, 10, 5);
//console.log('Now row_col is equal to the what recurGenCol returns when it is called with ' + (col + 1) + ' as the first argument.');
var row_row = [];
for (i = 0; i < 10; i++) {
// Does ten pushes to row_row with whatever row_col is...
row_row.push(row_col);
}
// Returns back to initArray() with whatever row_row is...
console.log('Going to return to '+arguments.callee.caller.name+' with row_row.');
return row_row;
}
// INIT:
var imageArray = initArray();
//console.log(imageArray);
// First level is imageArray,
// Second level is row_row,
// Third level is row_col
imageArray[0][0][0][0] = 'image_0_0_0_0.jpg';
imageArray[0][0][0][1] = 'image_0_0_0_1.jpg';
imageArray[0][0][0][2] = 'image_0_0_0_2.jpg';
//console.log( imageArray[0][0][0][1]);
imageArray[0][0][0][3] = 'image_0_0_0_3.jpg';
imageArray[0][0][0][4] = 'image_0_0_0_4.jpg';
imageArray[0][0][1][0] = 'image_0_0_1_0.jpg';
var img = imageArray[0][0][1][0];
// We expect this to log 'image_0_0_1_0.jpg'
// and it does so
console.log("first: " + img);
imageArray[0][0][1][1] = 'image_0_0_1_1.jpg';
imageArray[0][0][1][2] = 'image_0_0_1_2.jpg';
imageArray[0][0][1][3] = 'image_0_0_1_3.jpg';
imageArray[0][0][2][0] = 'image_0_0_2_0.jpg';
imageArray[0][0][2][1] = 'image_0_0_2_1.jpg';
imageArray[0][0][2][2] = 'image_0_0_2_2.jpg';
imageArray[0][0][3][3] = 'image_0_0_2_3.jpg';
imageArray[0][0][3][0] = 'image_0_0_3_0.jpg';
imageArray[0][0][3][1] = 'image_0_0_3_1.jpg';
imageArray[0][0][3][2] = 'image_0_0_3_2.jpg';
imageArray[0][0][3][3] = 'image_0_0_3_3.jpg';
imageArray[0][1][0][0] = 'image_0_1_0_0.jpg';
imageArray[0][2][0][0] = 'image_0_2_0_0.jpg';
imageArray[0][3][0][0] = 'image_0_3_0_0.jpg';
imageArray[0][3][0][1] = 'image_0_3_0_1.jpg';
imageArray[0][3][0][2] = 'image_0_3_0_2.jpg';
imageArray[0][3][0][3] = 'image_0_3_0_3.jpg';
imageArray[1][0][0][0] = 'image_1_0_0_0.jpg';
imageArray[1][0][0][1] = 'Image_1_0_0_1.jpg';
imageArray[1][0][0][2] = 'image_1_0_0_2.jpg';
imageArray[2][0][0][0] = 'image_2_0_0_0.jpg';
imageArray[2][0][0][1] = 'image_2_0_0_1.jpg';
imageArray[2][0][0][2] = 'image_2_0_0_2.jpg';
imageArray[2][0][0][3] = 'image_2_0_0_3.jpg';
imageArray[2][1][0][0] = 'image_2_1_0_0.jpg';
imageArray[2][1][0][1] = 'image_2_1_0_1.jpg';
//imageArray[6][1][0][1] = 'image_2_1_0_1.jpg';
img = imageArray[0][0][1][0];
// We expect this to log 'mage_0_0_1_0.jpg' but it DOESN'T!!!.
console.log("second: " + img);
// Rules that are true:
// - At 1st level, no items are the same object
// - At 2nd and 3rd level, all items within each parent array are the same object
// - At the last level, same-index values are the same object, except if the first level array is different
console.log('Is imageArray[0][0][0][1] the same object as imageArray[0][0][0][2]?');
console.log(imageArray[0][0][0][1] === imageArray[0][0][0][2]);
console.log('Is imageArray[0][0][0][1] the same object as imageArray[0][0][1][1]?');
console.log(imageArray[0][0][0][1] === imageArray[0][0][1][1]);
console.log('Is imageArray[0][0][0][1] the same object as imageArray[0][0][1][2]?');
console.log(imageArray[0][0][0][1] === imageArray[0][0][1][2]);
console.log('Is imageArray[0][0][0][2] the same object as imageArray[0][0][1][2]?');
console.log(imageArray[0][0][0][2] === imageArray[0][0][1][2]);
console.log('Is imageArray[0][0][0][1] the same object as imageArray[0][1][0][1]?');
console.log(imageArray[0][0][0][1] === imageArray[0][1][0][1]);
console.log('Is imageArray[0][0][0][1] the same object as imageArray[1][0][0][1]?');
console.log(imageArray[0][0][0][1] === imageArray[1][0][0][1]);
console.log('Is imageArray[0][0][1] the same object as imageArray[0][0][2]?');
console.log(imageArray[0][0][1] === imageArray[0][0][2]);
console.log('Is imageArray[0][1] the same object as imageArray[0][2]?');
console.log(imageArray[0][1] === imageArray[0][2]);

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