User:Zuhui/SI26/Storybook/Code to work 2: Difference between revisions
No edit summary |
|||
(14 intermediate revisions by the same user not shown) | |||
Line 18: | Line 18: | ||
</p> | </p> | ||
<div id=" | <div id="space"> | ||
<div class="do"></div> | <div class="do"></div> | ||
<div class="tigers | <div class="tigers"></div> | ||
<div class="melt | <div class="melt"></div> | ||
<div class="like"></div> | <div class="like"></div> | ||
<div class="butter | <div class="butter"></div> | ||
<div class="in"></div> | <div class="in"></div> | ||
<div class="the"></div> | <div class="the"></div> | ||
<div class="forest | <div class="forest"></div> | ||
<div class="questionmark"></div> | <div class="questionmark"></div> | ||
</div> | </div> | ||
Line 56: | Line 56: | ||
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 | 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 112: | Line 112: | ||
<br> | <br> | ||
<br> | <br> | ||
===two innerWidth variables and "resize" eventlistener=== | ===two innerWidth variables and "resize" eventlistener=== | ||
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
Line 136: | 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
<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
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.
DOM
JavaScript Creating New HTML Elements (Nodes) there's a fantastic example here!!
createTextNode() w3c
insertBefore() w3c
insertBefore() example w3c
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
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 theclassList.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
- ↳ using CSS selector
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);
}
}
find() mdn
findIndex() mdn
iterative methods (using callbacks) mdn
classList.contains() mdn
Callback function
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 usingsplice()[0]
how callback works here:
- in
removedDivs
array, find thedivs
that containsfindSameName
token - if the syntax returns
false
, it moves on to the nextdiv
- if the syntax returns
true
, it returns thatdiv
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
});