User:Zuhui/SI26/Storybook/Code to work 2: Difference between revisions

From XPUB & Lens-Based wiki
No edit summary
 
(16 intermediate revisions by the same user not shown)
Line 18: Line 18:
     </p>  
     </p>  


     <div id="stage">
     <div id="space">
         <div class="do"></div>
         <div class="do"></div>
         <div class="tigers object"></div>
         <div class="tigers"></div>
         <div class="melt object"></div>
         <div class="melt"></div>
         <div class="like"></div>
         <div class="like"></div>
         <div class="butter object"></div>
         <div class="butter"></div>
         <div class="in"></div>
         <div class="in"></div>
         <div class="the"></div>
         <div class="the"></div>
         <div class="forest object"></div>
         <div class="forest"></div>
         <div class="questionmark"></div>
         <div class="questionmark"></div>
     </div>
     </div>
Line 43: Line 43:
<br>
<br>
<br>
<br>
'''basic variables'''
===basic variables===
<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript">
let sentence = document.getElementById("sentence")//this is added from the first version, in the first version, I didn’t define "sentence", so there was no way to know where to put the words back from removedWords in "bringBack"function.
let sentence = document.getElementById("sentence")//this is added from the first version, in the first version, I didn’t define "sentence", so there was no way to know where to put the words back from removedWords in "bringBack"function.
Line 51: Line 51:
<br>
<br>
<br>
<br>
'''randomly removing, bringing words back function'''
===randomly removing, bringing words back function===
<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript">
function removeRandomWord () {
function removeRandomWord () {
     if (words.length > 1) {
     if (words.length > 1) {
         let pickRandom = Math.floor(Math.random() * words.length);
         let pickRandom = Math.floor(Math.random() * words.length);
         let remove = words.splice(pickRandom,1)[0]; //had to add "[0]" to pull the word out of the array and turn it into node. switching between nodelists and arrays requires extra steps
         let remove = words.splice(pickRandom,1)[0]; //had to add "[0]" to pull the first word out from the array
         removedWords.push(remove);
         removedWords.push(remove);
         remove.remove(); //.remove() method removes the element from the DOM.
         remove.remove(); //.remove() method removes the element from the DOM.
Line 91: Line 91:
:: ↳ this means the original span elements are no longer treated as elements, but instead they got converted into plain text.
:: ↳ this means the original span elements are no longer treated as elements, but instead they got converted into plain text.
: ↳ my spans are DOM node/elements, they should not be rendered as raw text. I need to use DOM methods again for appendchild() instead of DOM properties to control the elements directly with js.
: ↳ my spans are DOM node/elements, they should not be rendered as raw text. I need to use DOM methods again for appendchild() instead of DOM properties to control the elements directly with js.
<div style="float:right; text-align:right;">
[[User:Zuhui//Prototyping/Javascript#DOM | DOM]]<br>
[http://www.w3schools.com/JS/js_htmldom_nodes.asp JavaScript Creating New HTML Elements (Nodes)] there's a fantastic example here!!<br>
[https://www.w3schools.com/jsref/met_document_createtextnode.asp createTextNode() w3c]<br>
[http://www.w3schools.com/JS/js_htmldom_nodes.asp insertBefore() w3c]<br>
[http://www.w3schools.com/JS/tryit.asp?filename=tryjs_dom_elementcreate2 insertBefore() example w3c]<br>
</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
'''two innerWidth variables and "resize" eventlistener'''
<syntaxhighlight lang="javascript">
sentence.appendChild(document.createTextNode(" "));
</syntaxhighlight>
it works.
<br>
<br>
<br>
<br>
 
===two innerWidth variables and "resize" eventlistener===
<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript">
let prevWidth = window.innerWidth;
let prevWidth = window.innerWidth;
</syntaxhighlight>
</syntaxhighlight>
first defined prevWidth as innerWidth outside of the eventlistener
first define prevWidth as innerWidth outside of the eventlistener


<syntaxhighlight lang="javascript">
<syntaxhighlight lang="javascript">
Line 117: Line 137:
});
});
</syntaxhighlight>
</syntaxhighlight>
<br>
<br>
<br>
===break===
[[File:Undefined butter.png|1000px]]
<br>
<br>
<br>
<br>
===synchronizing spans and divs===
added basic variables for the divs
<syntaxhighlight lang="javascript">
let sentence = document.getElementById("sentence");
let space = document.getElementById("space");
let words = Array.from(document.querySelectorAll("#sentence span"));
let figures = Array.from(document.querySelectorAll("#space div"));
let removedWords = [];
let removedDivs = [];
</syntaxhighlight>
<br><br>
===adding the matching div under function removeRandom()===
with Joseph's help,
<syntaxhighlight lang="javascript">
function removeRandom () {
    if (words.length > 1) {
        let pickRandom = Math.floor(Math.random() * words.length);
        let removingWords = words.splice(pickRandom,1)[0];
        removedWords.push(removingWords);
        removingWords.remove();
       
 
        var findSameName = removingWords.classList[0].replace("word_","");
        let matchingDiv = document.querySelector("#space div." + findSameName);
        removedDivs.push(matchingDiv);
        matchingDiv.remove();
    }
}
</syntaxhighlight>
<div style="float:right; text-align:right;">
[[User:Zuhui//Prototyping/Javascript#DOMTokenList |DOMTokenList]]<br>
[https://developer.mozilla.org/en-US/docs/Web/API/Element/classList classList mdn]<br>
[https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList classList.replace() mdn]<br>
</div>
<br>
<br>
<br>
<br>
<br>
'''code explained:'''<br><br>
just like how <code>Array.from()</code> converts a NodeList to an array, which allowing the use of array methods,<code>classList</code> provides DOMToeknList, which allows the use of tokenlist methods.<br>
<syntaxhighlight lang="javascript">
var findSameName = removingWords.classList[0].replace("word_","");
</syntaxhighlight>
: ↳ <code>element.classList[0]</code> takes the first class name out from the DOMTokenList, and then use the <code>classList.replace()</code> method to modify the name.
<br>
<br>
<syntaxhighlight lang="javascript">
let matchingDiv = document.querySelector("#space div." + findSameName);
</syntaxhighlight>
: ↳ <code>document.querySelector</code> to find a single, specific element in the DOM
:: ↳ using CSS selector <code>+</code> inside the parentheses
<br>
<br>
<br>
<br>
===adding the matching div under function bringBackRandom()===
<syntaxhighlight lang="javascript">
function bringBackRandom () {
    if (removedWords.length > 0) {
        let pickRandom = Math.floor(Math.random() * removedWords.length);
        let bringBackWord = removedWords.splice(pickRandom, 1)[0];
        words.push(bringBackWord);
        sentence.appendChild(bringBackWord);
        sentence.appendChild(document.createTextNode(" "));
        var findSameName = bringBackWord.classList[0].replace("word_","");
        let matchingDiv = removedDivs.find(div => div.classList.contains(findSameName));
        figures.push(matchingDiv);
        space.appendChild(matchingDiv);
    }
}
</syntaxhighlight>
<div style="float:right; text-align:right;">
[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find find() mdn]<br>
[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex findIndex() mdn]<br>
[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array#iterative_methods iterative methods (using callbacks) mdn]<br>
[https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/contains classList.contains() mdn]<br>
[[User:Zuhui//Prototyping/Javascript#Callback |Callback function]]<br>
</div>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
'''code explained:'''
<syntaxhighlight lang="javascript">
let matchingDivv = removedDivs.find(div => div.classList.contains(findSameName));
</syntaxhighlight>
* <code>find()</code> is one of the ''' ''iterative methods'' '''
: ↳ "Iterative methods always use a '''callback function to loop through each item in an array and process it'''."
: ↳ but find() doesn't always use callback function
* <code>findIndex()</code> also works, but you need an extra line to remove/retrieve the element from the array using <code>splice()[0]</code>
<br>
'''how callback works here:'''<br>
* in <code>removedDivs</code> array, find the <code>divs</code> that contains <code>findSameName</code> '''token'''
* if the syntax returns <code>false</code>, it moves on to the next <code>div</code>
* if the syntax returns <code>true</code>, it returns that <code>div</code> and stops.
<br>
'''instead of "=>"'''<br>
seems like the arrow function is mostly used for convenience because it omits <code>function</code> and <code>return</code> when there's only one return, but it's still confusing to write it myself
<syntaxhighlight lang="javascript">
let matchingDiv = removedDivs.find(function(div) {return div.classList.contains(findSameName)});
</syntaxhighlight>
<div style="float:right; text-align:right;">
[https://www.w3schools.com/js/js_arrow_function.asp arrow function w3c]<br>
</div>
<br>
<br>
<br>
===Working code===
<syntaxhighlight lang="javascript">
let sentence = document.getElementById("sentence");
let space = document.getElementById("space");
let words = Array.from(document.querySelectorAll("#sentence span"));
let figures = Array.from(document.querySelectorAll("#space div"));
let removedWords = [];
let removedDivs = [];
function removeRandom () {
    if (words.length > 1) {
        let pickRandom = Math.floor(Math.random() * words.length);
        let removingWords = words.splice(pickRandom,1)[0];//had to add "[0]" to pull the word out from the array
        //console.log(removingWords);
        removedWords.push(removingWords);
        removingWords.remove(); //.remove() method removes the element from the DOM.
       
       
        //now find the same named divs
        var findSameName = removingWords.classList[0].replace("word_","");
        //console.log(findSameName);
        let matchingDiv = document.querySelector("#space div." + findSameName);//only need one matching div
        //console.log(matchingDiv);
        removedDivs.push(matchingDiv);
        matchingDiv.remove();
        //console.log(removedDivs);
    }
}
function bringBackRandom () {
    if (removedWords.length > 0) {
        let pickRandom = Math.floor(Math.random() * removedWords.length);
        let bringBackWord = removedWords.splice(pickRandom, 1)[0];
        words.push(bringBackWord);
        sentence.appendChild(bringBackWord);
        sentence.appendChild(document.createTextNode(" ")); //this works, needed a method that directly manipulates the dom tree
        //now bring back the matching divs
        var findSameName = bringBackWord.classList[0].replace("word_","");
        let matchingDiv = removedDivs.find(div => div.classList.contains(findSameName));
        //console.log(matchingDiv);
        figures.push(matchingDiv);
        space.appendChild(matchingDiv);
        //console.log(removedDivs);
    }
}
//save the innerWidths into two variables
let prevWidth = window.innerWidth;
//when the innerWidth is reduced by more than 100px, remove one random word
window.addEventListener("resize", () => {
    let currWidth = window.innerWidth;
    let widthChange = Math.abs(prevWidth - currWidth);
    //console.log(widthChange)
    if (currWidth < prevWidth && widthChange > 100) {
        removeRandom();
        prevWidth = currWidth;
    }
    else if (prevWidth < currWidth && widthChange > 100) {
        bringBackRandom();
        prevWidth = currWidth;
    }
    //instead of updating prevWidth at the very end of the function once, update it inside each if statement
});
</syntaxhighlight>
<br>
<br>

Latest revision as of 09:25, 15 March 2025

Html structure


previous version

<body>
    <p id="sentence">
        <span class="word_do">do</span>
        <span class="word_tigers">tigers</span>
        <span class="word_melt">melt</span>
        <span class="word_like">like</span>
        <span class="word_butter">butter</span>
        <span class="word_in">in</span>
        <span class="word_the">the</span>
        <span class="word_forest">forest</span>
        <span class="word_questionmark">?</span>
    </p> 

    <div id="space">
        <div class="do"></div>
        <div class="tigers"></div>
        <div class="melt"></div>
        <div class="like"></div>
        <div class="butter"></div>
        <div class="in"></div>
        <div class="the"></div>
        <div class="forest"></div>
        <div class="questionmark"></div>
    </div>
   
    <script src="java1.js"></script>
</body>

now all the divs are also siblings, so they will listen to same command that controls the spans(words)


Javascript


previous version

basic variables

let sentence = document.getElementById("sentence")//this is added from the first version, in the first version, I didn’t define "sentence", so there was no way to know where to put the words back from removedWords in "bringBack"function.
let words = Array.from(document.querySelectorAll("#sentence span"));
let removedWords = [];



randomly removing, bringing words back function

function removeRandomWord () {
    if (words.length > 1) {
        let pickRandom = Math.floor(Math.random() * words.length);
        let remove = words.splice(pickRandom,1)[0]; //had to add "[0]" to pull the first word out from the array
        removedWords.push(remove);
        remove.remove(); //.remove() method removes the element from the DOM.
    }
}

function bringbackRandomWord () {
    if (removedWords.length > 0) {
        let pickRandom = Math.floor(Math.random() * removedWords.length);
        let bringBack = removedWords.splice(pickRandom,1)[0];
        words.push(bringBack);
        sentence.innerHTML = sentence.innerHTML + " "; //try to add space between the spans but this doesn't work at the moment.
        sentence.appendChild(bringBack); //opposite of remove() is appendChild()
    }
}
↳ how do I add a space (" ") after each word that is brought back?
sentence.innerHTML += " ";
↳ this works only the first time shrinking the browser, but when i try again, it stops working. then at some point, it starts adding more words. as if the words are duplicating itself





  • I think appendChild() should be a way to go. Just like how I brought the spans back with that method. But using it with properties like innerHTML, innerText, textContent, doesn’t work.
↳ throwing spaghetties on the wall approach using those 3 properties around the line did work at some point in terms of adding spaces in between my spans, but the browser rendered all my spans as [object HTMLSpanElement]. technically doesn’t work, but it’s something.
↳ so [object HTMLSpanElement] means it broke the structure of my spans and turned them into raw text within sentence.innerHTML
↳ this means the original span elements are no longer treated as elements, but instead they got converted into plain text.
↳ my spans are DOM node/elements, they should not be rendered as raw text. I need to use DOM methods again for appendchild() instead of DOM properties to control the elements directly with js.







sentence.appendChild(document.createTextNode(" "));

it works.



two innerWidth variables and "resize" eventlistener

let prevWidth = window.innerWidth;

first define prevWidth as innerWidth outside of the eventlistener

window.addEventListener("resize", () => {
    let currWidth = window.innerWidth;
    let widthChange = Math.abs(prevWidth - currWidth);
    console.log(widthChange)

    if (currWidth < prevWidth && widthChange > 100) {
        removeRandomWord();
        prevWidth = currWidth;
    }
    else if (prevWidth < currWidth && widthChange > 100) {
        bringbackRandomWord();
        prevWidth = currWidth;
    }
     //instead of updating prevWidth at the very end of the function, update it inside each if statement
     //previous version was updating currWidth to prevWidth, i thought i was saving the currWidth to prevWidth but it works other way around.
});




break

Undefined butter.png



synchronizing spans and divs

added basic variables for the divs

let sentence = document.getElementById("sentence");
let space = document.getElementById("space");

let words = Array.from(document.querySelectorAll("#sentence span"));
let figures = Array.from(document.querySelectorAll("#space div"));

let removedWords = [];
let removedDivs = [];



adding the matching div under function removeRandom()

with Joseph's help,

function removeRandom () {
    if (words.length > 1) {
        let pickRandom = Math.floor(Math.random() * words.length);
        let removingWords = words.splice(pickRandom,1)[0];
        removedWords.push(removingWords);
        removingWords.remove();
        
   
        var findSameName = removingWords.classList[0].replace("word_","");
        let matchingDiv = document.querySelector("#space div." + findSameName);
        removedDivs.push(matchingDiv);
        matchingDiv.remove();
    }
}






code explained:

just like how Array.from() converts a NodeList to an array, which allowing the use of array methods,classList provides DOMToeknList, which allows the use of tokenlist methods.

var findSameName = removingWords.classList[0].replace("word_","");
element.classList[0] takes the first class name out from the DOMTokenList, and then use the classList.replace() method to modify the name.



let matchingDiv = document.querySelector("#space div." + findSameName);
document.querySelector to find a single, specific element in the DOM
↳ using CSS selector + inside the parentheses





adding the matching div under function bringBackRandom()

function bringBackRandom () {
    if (removedWords.length > 0) {
        let pickRandom = Math.floor(Math.random() * removedWords.length);
        let bringBackWord = removedWords.splice(pickRandom, 1)[0];
        words.push(bringBackWord);
        sentence.appendChild(bringBackWord); 
        sentence.appendChild(document.createTextNode(" "));


        var findSameName = bringBackWord.classList[0].replace("word_","");
        let matchingDiv = removedDivs.find(div => div.classList.contains(findSameName));
        figures.push(matchingDiv);
        space.appendChild(matchingDiv);
    }
}








code explained:

let matchingDivv = removedDivs.find(div => div.classList.contains(findSameName));
  • find() is one of the iterative methods
↳ "Iterative methods always use a callback function to loop through each item in an array and process it."
↳ but find() doesn't always use callback function
  • findIndex() also works, but you need an extra line to remove/retrieve the element from the array using splice()[0]


how callback works here:

  • in removedDivs array, find the divs that contains findSameName token
  • if the syntax returns false, it moves on to the next div
  • if the syntax returns true, it returns that div and stops.


instead of "=>"
seems like the arrow function is mostly used for convenience because it omits function and return when there's only one return, but it's still confusing to write it myself

let matchingDiv = removedDivs.find(function(div) {return div.classList.contains(findSameName)});




Working code

let sentence = document.getElementById("sentence");
let space = document.getElementById("space");

let words = Array.from(document.querySelectorAll("#sentence span"));
let figures = Array.from(document.querySelectorAll("#space div"));

let removedWords = [];
let removedDivs = [];


function removeRandom () {
    if (words.length > 1) {
        let pickRandom = Math.floor(Math.random() * words.length);
        let removingWords = words.splice(pickRandom,1)[0];//had to add "[0]" to pull the word out from the array
        //console.log(removingWords);
        removedWords.push(removingWords);
        removingWords.remove(); //.remove() method removes the element from the DOM.
        
        

        //now find the same named divs
        var findSameName = removingWords.classList[0].replace("word_","");
        //console.log(findSameName);
        let matchingDiv = document.querySelector("#space div." + findSameName);//only need one matching div
        //console.log(matchingDiv);
        removedDivs.push(matchingDiv);
        matchingDiv.remove();
        //console.log(removedDivs);
    }
}

function bringBackRandom () {
    if (removedWords.length > 0) {
        let pickRandom = Math.floor(Math.random() * removedWords.length);
        let bringBackWord = removedWords.splice(pickRandom, 1)[0];
        words.push(bringBackWord);
        sentence.appendChild(bringBackWord); 
        sentence.appendChild(document.createTextNode(" ")); //this works, needed a method that directly manipulates the dom tree


        //now bring back the matching divs
        var findSameName = bringBackWord.classList[0].replace("word_","");
        let matchingDiv = removedDivs.find(div => div.classList.contains(findSameName));
        //console.log(matchingDiv);
        figures.push(matchingDiv);
        space.appendChild(matchingDiv);
        //console.log(removedDivs);
    }
}

//save the innerWidths into two variables
let prevWidth = window.innerWidth;
//when the innerWidth is reduced by more than 100px, remove one random word
window.addEventListener("resize", () => {
    let currWidth = window.innerWidth;
    let widthChange = Math.abs(prevWidth - currWidth);
    //console.log(widthChange)

    if (currWidth < prevWidth && widthChange > 100) {
        removeRandom();
        prevWidth = currWidth;
    }
    else if (prevWidth < currWidth && widthChange > 100) {
        bringBackRandom();
        prevWidth = currWidth;
    }
    //instead of updating prevWidth at the very end of the function once, update it inside each if statement
});