This code fetches multiple words from the same arrays of words and parse it into HTML. Inside the get_word function, how can I avoid the same word from being selected and printed multiple times?
NO: Car, Car, House, Cat
YES: Car, Dog, House, Cat
var words = ["Buss", "Plane", "Car","Dog","Cat", "House"];
get_random = function (list) {
return list[Math.floor((Math.random()*list.length))];
}
get_word = function (number) {
for (i = 1; i < number+1; i++) {
word = get_random(words);
document.getElementById("word"+i).innerHTML = word;
}
}
start = function () {
get_word(3);
}
div.buttons {
text-align: center;
margin: 15px;
}
.button {
background-color: #4CAF50;
/* Green */
border: none;
color: white;
padding: 15px 32px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 16px;
}
#word1,
#word2,
#word3,
#word4 {
text-align: center;
font-size: 48px;
color: red;
bottom: 15px;
}
<div id="word1"></div>
<div id="word2"></div>
<div id="word3"></div>
<div id="word4"></div>
<div class="buttons">
<button class="button" onclick="start();">Try it</button>
</div>
I aggree with hoangdv but it can be event simpler
const words = ["Bus", "Plane", "Car","Dog","Cat", "House"];
function shuffle(array) {
array.sort(() => Math.random() - 0.5);
return array
}
get_word = function (number) {
return shuffle(words).slice(0,number)
}
console.log(get_word(3))
console.log(get_word(3))
console.log(get_word(3))
I think the solution to your problem is using pop(), although you will need to make sure that you keep a copy of your original list somewhere if you need to reference it later, as pop will change the list and reduce its length.
This means your function get_random should look closer to:
get_random = function (list)
{
return list.pop(Math.floor((Math.random()*list.length)))
}
I think you can shuffle the array then get get each item of the the shuffled array.
function shuffle(array) {
array.sort(() => Math.random() - 0.5);
}
get_word = function (number) {
shuffle(words);
for (i = 1; i < number+1; i++) {
word = words[i - 1];
document.getElementById("word"+i).innerHTML = word;
}
}
Add an extra variable can resolve the issue.
get_word = function (number) {
var out = [];
for (i = 1; i < number+1; i++) {
word = get_random(words);
if(out.findIndex(w=>w==word) > -1){
out.push(word);
document.getElementById("word"+i).innerHTML = word;
}
}
}
Related
Similar question : But can't able to get answer
Can be answer to this question : But has to split on each :
If possible to get all variable in one function and change each values
If there are 2-4 variable than easy to change but when that change to 10 or more
var root = document.querySelector(':root');
function func() {
root.style.setProperty('--r', 'brown');
root.style.setProperty('--b', 'lightblue');
root.style.setProperty('--g', 'lightgreen');
}
:root {
--r: red;
--b: blue;
--g: green;
}
.text1 {
color: var(--r)
}
.text2 {
color: var(--b)
}
.text3 {
color: var(--g)
}
<div class="text1">Hello</div>
<div class="text2">Bye</div>
<div class="text3">World</div>
<button onclick="func()">Change</button>
Is there a way to automatic(dynamically) get all the variables without writing each variable while values array is self entered
var root = document.querySelector(':root');
var roots = getComputedStyle(root);
var re = roots.getPropertyValue('--r')
var bl = roots.getPropertyValue('--b')
var gr = roots.getPropertyValue('--g')
function func() {
root.style.setProperty('--r', 'brown');
root.style.setProperty('--b', 'lightblue');
root.style.setProperty('--g', 'lightgreen');
}
function func2() {
root.style.setProperty('--r', re);
root.style.setProperty('--b', bl);
root.style.setProperty('--g', gr);
}
:root {
--r: red;
--b: blue;
--g: green;
}
.text1 {
color: var(--r)
}
.text2 {
color: var(--b)
}
.text3 {
color: var(--g)
}
<div class="text1">Hello</div>
<div class="text2">Bye</div>
<div class="text3">World</div>
<button onclick="func()">Change</button>
<button onclick="func2()">Orignal</button>
But when getting back to original values then each value is entered by separate variable and for each it is defined .
Is there a way to have a approach which takes original values and variables in separate array automatically.
Thanks for help in advance
I understand you want to first read all the declared variables from the css and store them, so they might be resetted after applying new values?
This code will do this, given that there's just one ':root' declaration in one stylesheet (easily complemented in case 'splitted' declaration in more places needed)
let variableLookup = {
'--r': {
newValue: 'teal'
},
'--b': {
newValue: 'orange'
},
'--g': {
newValue: 'purple'
}
}
var root = document.querySelector(':root');
function setNewColors() {
const cssText = [...document.styleSheets]
.map(styleSheet => [...styleSheet.cssRules]
.filter(CSSStyleRule => CSSStyleRule.selectorText === ':root'))
.flat()[0].cssText
// cssText = ':root { --r: red; --b: blue; --g: green; }'
cssText.match(/{(.*)}/)[1].trim()
.split(';')
.filter(Boolean)
.forEach(declaration => {
const [variable, oldValue] = declaration.split(':').map(str => str.trim())
let entry = variableLookup[variable]
if (entry) entry.oldValue = oldValue
})
console.log('variableLookup >>', variableLookup)
Object.entries(variableLookup).forEach(([variable, {newValue}]) => {
root.style.setProperty(variable, newValue);
})
}
function resetColors() {
Object.entries(variableLookup).forEach(([variable, {oldValue}]) => {
if (oldValue) root.style.setProperty(variable, oldValue)
})
}
:root {
--r: red;
--b: blue;
--g: green;
}
.text1 {
color: var(--r)
}
.text2 {
color: var(--b)
}
.text3 {
color: var(--g)
}
:root {
--c: magenta;
}
<div class="text1">Hello</div>
<div class="text2">Bye</div>
<div class="text3">World</div>
<button onclick="setNewColors()">Change to new colors</button>
<button onclick="resetColors()">Reset old colors</button>
Since the OP is interested in a version without using .split() these could be replaced by using a regex and .match()
const declarations = '--r: red; --b: blue; --g: green;'
const regex1 = /^[\w-:\s]+(?=;)|(?<=;)[\w-:\s]+/g
const declarationsArr = declarations.match(regex1)
console.log(declarationsArr) // ["--r: red", " --b: blue", " --g: green"]
const regex2 = /[\w-]+(?=:)|(?<=:\s)[\w-]+/g
const declarationsSplit = declarationsArr.map(d => d.match(regex2))
console.log(declarationsSplit) // [["--r", "red"], ["--b", "blue"], ["--g", "green"]]
One method can be entering all variables and values in different arrays and fetching values from them . Where variables = values which need to be equal have same index number
var root = document.querySelector(':root');
variable = ['--r', '--b', '--g'];
values = ['violet', 'lightblue', 'lightgreen']
function func() {
for (let i = 0; i < 3; i++)
root.style.setProperty(variable[i], values[i]);
}
:root {
--r: red;
--b: blue;
--g: green;
}
.text1 {
color: var(--r)
}
.text2 {
color: var(--b)
}
.text3 {
color: var(--g)
}
<div class="text1">Hello</div>
<div class="text2">Bye</div>
<div class="text3">World</div>
<button onclick="func()">Change</button>
const root = document.documentElement;
function changeVariables(...values) {
const variables = ["--r", "--g", "--b"];
for (const variable of variables) {
root.style.setProperty(variable, values[variable.indexof(variables)]);
}
}
//Simply execute function like this
changeVariables("#000", "#808080", "#FF0000");
setting new-colors you want to change
backup original-colors
Try the example bellow
var root = document.querySelector(':root');
var $divEle = $("div[class^='text']"); // get all element with class starting with 'text'
var arrCssVar = ['--r', '--b','--g'];
var backupOrgColor= {}
var newColor = {'--r':'brown', '--b':'lightblue', '--g':'lightgreen'}; // ordering color what you want to change
// backup original colors
$divEle.map(function(i, v) {
if(i < arrCssVar.length){
var compStyle = getComputedStyle(this);
// setting key/value pair to Obj
backupOrgColor[arrCssVar[i]] = compStyle.getPropertyValue(arrCssVar[i]);
}
});
// change color
function setNewColors() {
arrCssVar.map(function (key, value) {
//console.log(key + ": key :change: value : "+ newColor[key]);
root.style.setProperty(key, newColor[key]);
});
}
// reset original color
function resetColors() {
arrCssVar.map(function (key, value) {
//console.log(key + ": key :: value : "+ backupOrgColor[key]);
root.style.setProperty(key, backupOrgColor[key]);
});
}
:root {
--r: red;
--b: blue;
--g: green;
}
.text1 {
color: var(--r)
}
.text2 {
color: var(--b)
}
.text3 {
color: var(--g)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="text1">Hello</div>
<div class="text2">Bye</div>
<div class="text3">World</div>
<button onclick="setNewColors()">Change</button>
<button onclick="resetColors()">Orignal</button>
Try this example.
Initialize two arrays, one is empty for the current colors form the css and second for a new colors.
Need to define how many variables, then get them and put in an empty array.
Create two functions with loops, in the first we assign the new colors for variables, in the second reset.
const root = document.body;
// Colors arrays
const cssVarColors = [];
const newColors = ['brown', 'lightblue', 'lightgreen'];
// Create an array of variable colors from css.
const cssRootArray = document.styleSheets[0].cssRules;
for (const i of cssRootArray) {
// Check, if :root in the css.
if (i.selectorText.includes('root')) {
const rootArrayLength = i.style.length;
for (let j = 0; j < rootArrayLength; j++) {
const key = i.style[j];
// Create object { key/variable : value/color }
const value = getComputedStyle(root).getPropertyValue(key);
cssVarColors.push({[key]: value});
}
}
}
// We change colors, with variable keys and indexes.
function changeColor() {
for (const i in cssVarColors) {
const key = Object.keys(cssVarColors[i]);
// Check, if newColor array don't have a color.
if (!newColors[i]) {
return;
}
root.style.setProperty(key, newColors[i]);
}
variables();
}
change.addEventListener('click', changeColor);
const root = document.body;
// Colors arrays
const cssVarColors = [];
const newColors = ['brown', 'lightblue', 'lightgreen'];
// Create an array of colors from a css variables file.
const cssRootArray = document.styleSheets[0].cssRules;
for (const i of cssRootArray) {
// Check, if :root in the css.
if (i.selectorText.includes('root')) {
const rootArrayLength = i.style.length;
for (let j = 0; j < rootArrayLength; j++) {
const key = i.style[j];
// Create object { key/variable : value/color }
const value = getComputedStyle(root).getPropertyValue(key);
cssVarColors.push({
[key]: value,
});
}
}
}
// We change colors, with variable keys and indexes.
function changeColor() {
for (const i in cssVarColors) {
const key = Object.keys(cssVarColors[i]);
// Check, if newColor array don't have a color.
if (!newColors[i]) {
return;
}
root.style.setProperty(key, newColors[i]);
}
variables();
}
// Can't separate in loop by [key, value],
// because key has a specific value.
function resetColor() {
for (const i in cssVarColors) {
if (!newColors[i]) {
return;
}
const key = Object.keys(cssVarColors[i]);
const value = Object.values(cssVarColors[i]);
root.style.setProperty(key, value);
}
variables();
}
// Change button
change.addEventListener('click', changeColor);
// Reset button
reset.addEventListener('click', resetColor);
// extra for view
cssVarColors.forEach(clr => {
const el = document.createElement('span');
el.textContent = JSON.stringify(clr);
document.getElementById('variables').appendChild(el);
});
:root {
--r: red;
--b: blue;
--g: green;
--m: magenta;
--black: black;
}
.text1 {
color: var(--r);
}
.text2 {
color: var(--b);
}
.text3 {
color: var(--g);
}
/* Extra style */
body {
display: grid;
grid-template-columns: 50px 150px;
grid-template-rows: auto;
}
section {
grid-column: 1;
}
#variables {
grid-column: 2;
display: flex;
flex-direction: column;
}
span:nth-of-type(1) {
border: 5px solid var(--r);
}
span:nth-of-type(2) {
border: 5px solid var(--b);
}
span:nth-of-type(3) {
border: 5px solid var(--g);
}
span:nth-of-type(4) {
border: 5px solid var(--m);
}
span:nth-of-type(5) {
border: 5px solid var(--black);
}
<section>
<div class="text1">Hello</div>
<div class="text2">Bye</div>
<div class="text3">World</div>
</section>
<div id="variables"></div>
<button id="change">Change</button>
<button id="reset">Reset</button>
I'm trying to create a quiz that tests users awareness of real and fake emails. What I want to do is have the question displayed at the top saying "Real or Fake", then have an image displayed underneath which the user needs to look at to decided if it's real or fake. There are two buttons, real and fake, and regardless of whether they choose the right answer I want to swap the original image with annotated version - showing how users could spot that it was fake or real.
But I'm not sure how to show the annotated version once the answer has been submitted. Could someone help?
function Quiz(questions) {
this.score = 0;
this.questions = questions;
this.questionIndex = 0;
}
Quiz.prototype.getQuestionIndex = function() {
return this.questions[this.questionIndex];
}
Quiz.prototype.guess = function(answer) {
if (this.getQuestionIndex().isCorrectAnswer(answer)) {
this.score++;
}
this.questionIndex++;
}
Quiz.prototype.isEnded = function() {
return this.questionIndex === this.questions.length;
}
function Question(text, choices, answer) {
this.text = text;
this.choices = choices;
this.answer = answer;
}
Question.prototype.isCorrectAnswer = function(choice) {
return this.answer === choice;
}
function populate() {
if (quiz.isEnded()) {
showScores();
} else {
// show question
var element = document.getElementById("question");
element.innerHTML = quiz.getQuestionIndex().text;
// show options
var choices = quiz.getQuestionIndex().choices;
for (var i = 0; i < choices.length; i++) {
var element = document.getElementById("choice" + i);
element.innerHTML = choices[i];
guess("btn" + i, choices[i]);
}
showProgress();
}
};
function guess(id, guess) {
var button = document.getElementById(id);
button.onclick = function() {
quiz.guess(guess);
populate();
}
};
function showProgress() {
var currentQuestionNumber = quiz.questionIndex + 1;
var element = document.getElementById("progress");
element.innerHTML = "Question " + currentQuestionNumber + " of " + quiz.questions.length;
};
function showScores() {
var gameOverHTML = "<h1>Result</h1>";
gameOverHTML += "<h2 id='score'> Your scores: " + quiz.score + "</h2>";
var element = document.getElementById("quiz");
element.innerHTML = gameOverHTML;
};
// create questions here
var questions = [
new Question("<img src= 'netflix_fake.jpg' />", ["Real", "Fake"], "Fake"),
new Question("<img src= 'dropbox_real.jpg' />", ["Real", "Fake"], "Real"),
new Question("<img src= 'gov_real.jpg' />", ["Real", "Fake"], "Real"),
new Question("<img src= 'paypal_fake.jpg' />", ["Real", "Fake"], "Fake"),
new Question("<img src= 'gmail.jpg' />", ["Real", "Fake"], "Fake")
];
//create quiz
var quiz = new Quiz(questions);
// display
populate();
body {
background-color: #538a70;
}
.grid {
width: 600px;
height: 500px;
margin: 0 auto;
background-color: #fff;
padding: 10px 50px 50px 50px;
border: 2px solid #cbcbcb;
}
.grid h1 {
font-family: "sans-serif";
font-size: 60px;
text-align: center;
color: #000000;
padding: 2px 0px;
}
#score {
color: #000000;
text-align: center;
font-size: 30px;
}
.grid #question {
font-family: "monospace";
font-size: 30px;
color: #000000;
}
.buttons {
margin-top: 30px;
}
#btn0,
#btn1,
#btn2,
#btn3 {
background-color: #a0a0a0;
width: 250px;
font-size: 20px;
color: #fff;
border: 1px solid #1D3C6A;
margin: 10px 40px 10px 0px;
padding: 10px 10px;
}
#btn0:hover,
#btn1:hover,
#btn2:hover,
#btn3:hover {
cursor: pointer;
background-color: #00994d;
}
#btn0:focus,
#btn1:focus,
#btn2:focus,
#btn3:focus {
outline: 0;
}
#progress {
color: #2b2b2b;
font-size: 18px;
}
<div class="grid">
<div id="quiz">
<h1>Can you spot the fake email?</h1>
<hr style="margin-bottom: 20px">
<p id="question"></p>
<div class="buttons">
<button id="btn0"><span id="choice0"></span></button>
<button id="btn1"><span id="choice1"></span></button>
</div>
<hr style="margin-top: 50px">
<footer>
<p id="progress">Question x of y</p>
</footer>
</div>
</div>
When user clicks button I trigger class and I add it second name, on second I have written to get swapped, I wrote you basically full project, and please read the whole comments, to understand logic
//Calling Elements from DOM
const button = document.querySelectorAll(".check");
const images = document.querySelectorAll(".image");
const answer = document.querySelector("h1");
//Declaring variable to randomly insert any object there to insert source in DOM Image sources
let PreparedPhotos;
//Our Images Sources and With them are its fake or not
//fake: true - yes its fake
//fake: false - no its real
const image = [
[
{
src:
"https://upload.wikimedia.org/wikipedia/commons/thumb/e/ec/Mona_Lisa%2C_by_Leonardo_da_Vinci%2C_from_C2RMF_retouched.jpg/1200px-Mona_Lisa%2C_by_Leonardo_da_Vinci%2C_from_C2RMF_retouched.jpg",
fake: true
},
{
src:
"http://graphics8.nytimes.com/images/2012/04/13/world/europe/mona-lisa-like-new-images/mona-lisa-like-new-images-custom4-v3.jpg",
fake: false
}
],
[
{
src:
"https://cdn.shopify.com/s/files/1/0849/4704/files/Creacion_de_Adan__Miguel_Angel_f5adb235-bfa8-4caa-8ffb-c5328cbad953_grande.jpg?12799626327330268216",
fake: false
},
{
src:
"https://cdn.shopify.com/s/files/1/0849/4704/files/First-image_Fb-size_grande.jpg?10773543754915177139",
fake: true
}
]
];
//Genrating Random Photo on HTML
function setRandomPhoto() {
//Random Number which will be length of our array of Object
//if you array includes 20 object it will generate random number
// 0 - 19
const randomNumber = Math.floor(Math.random() * image.length);
//Decalaring our already set variable as Array Object
PreparedPhoto = image[randomNumber];
//Our first DOM Image is Variables first object source
images[0].src = PreparedPhoto[0].src;
//and next image is next object source
images[1].src = PreparedPhoto[1].src;
}
//when windows successfully loads, up function runs
window.addEventListener("load", () => {
setRandomPhoto();
});
//buttons click
//forEach is High Order method, basically this is for Loop but when you want to
//trigger click use forEach - (e) is single button whic will be clicked
button.forEach((e) => {
e.addEventListener("click", () => {
//decalring variable before using it
let filtered;
//finding from our DOM image source if in our long array exists
//same string or not as Image.src
//if it exists filtered variable get declared with that found obect
for (let i = 0; i < image.length; i++) {
for (let k = 0; k < 2; k++) {
if (image[i][k].src === images[0].src) {
filtered = image[i][k];
}
}
}
//basic if else statement, if clicked button is Fake and image is true
//it outputs You are correct
//if clicked button is Real and Image is false it outputs Correct
//Else its false
//Our image checking comes from filtered variable
if (e.innerText === "Fake" && filtered.fake === true) {
answer.innerText = "You Are Correct";
images.forEach((image) => {
image.classList.toggle("hidden");
});
} else if (e.innerText === "Real" && filtered.fake === false) {
answer.innerText = "You Are Correct";
images.forEach((image) => {
image.classList.toggle("hidden");
});
} else {
answer.innerHTML = "You are Wrong";
images.forEach((image) => {
image.classList.toggle("hidden");
});
}
});
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
width: 100%;
min-height: 100vh;
display: flex;
justify-content: space-around;
align-items: center;
flex-direction: column;
}
.image-fluid {
display: flex;
}
.image-fluid .image {
width: 200px;
margin: 0 10px;
transition: 0.5s;
}
.image-fluid .image:nth-child(1).hidden {
transform: translateX(110px);
}
.image-fluid .image:nth-child(2).hidden {
transform: translateX(-110px);
}
<div class="container">
<div class="image-fluid">
<img src="" class="image hidden">
<img src="" class="image hidden">
</div>
<div class="button-fluid">
<button class="check">Fake</button>
<button class="check">Real</button>
</div>
</div>
<h1></h1>
Hey I'm a beginner in js. I wanted to do quick sorting function. I have tables with values and I would like to show how they change to show how the function works. Unfortunately the function is almost instantaneous so I did sleep function and added to the sorting function. After that the function didn't work in some cases (some values were unsorted) I think it might have something to do with recursion. Please help how can i do it better? :)
(Other functions like selection sort or bubble sort works properly)
var arr = new Array();
Array.prototype.swap = function (x,y) {
var temp = this[x];
this[x] = this[y];
this[y] = temp;
return this;
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function start_qs(){
for(i=0;i<10;i++){
var value = Math.floor(Math.random() * 100); // random integer from 0 - 100
arr[i] = value;
}
qs(arr, 0, arr.length - 1);
}
function update(effect_id, array){
document.getElementById(effect_id).innerHTML = "";
for(i=0;i<10;i++){
document.getElementById(effect_id).innerHTML += '<div class="label" style="height:'+array[i]+'px;">'+array[i]+'</div>';
}
}
async function qs(array, left, right){
let i = left;
let j = right;
x = array[Math.floor((left+right)/2)];
while(i<=j){
await sleep(50);
while(array[i] < x && i < right){i++;}
while(array[j] > x && j > left){j--;}
if(i <= j){
array.swap(i,j);
i++;
j--;
update("quicksort", arr);
}
}
if(left < j){qs(array, left, j);}
if(i < right){qs(array, i, right);}
}
window.onload = function(){start_qs();}
:root {
--main: #202020;
--sec: #D03737;
}
html{
background: var(--main);
color: var(--sec);
font-size: 28px;
}
body {
margin: 0;
padding: 0;
}
h3{text-align:center;}
.element{margin:auto;width:70%;}
.effect{width:60%;height:200px;margin:auto;}
.label{background: var(--sec); width:7%;margin:0 1.5%;color:black;text-align:center;font-size:0.75rem;}
<script type="text/javascript" src="js/quickSort.js"/></script>
<h2 style="text-align:center;">Javascript algorithms</h2>
<div class="element" id="quicksorting" >
<h3>Quick Sorting
<button style="border-radius:10px;padding:10px 30px;background:var(--main);border-color:var(--sec);color:var(--sec);" onclick="start_qs()">Restart</button></h3>
<div class="content" style="display:flex;">
<div class="effect" id="quicksort" style="display:flex;align-items:flex-end;">
</div>
</div>
</div>
Since you're calling the function recursively, you need to use await in the recursive calls. Otherwise the recursive calls will not execute until the current call finishes, and quicksort requires things all the recursive calls to execute in order.
Also declare x as a local variable, otherwise the recursive calls will overwrite its value.
var arr = new Array();
Array.prototype.swap = function(x, y) {
var temp = this[x];
this[x] = this[y];
this[y] = temp;
return this;
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function start_qs() {
for (i = 0; i < 10; i++) {
var value = Math.floor(Math.random() * 100); // random integer from 0 - 100
arr[i] = value;
}
qs(arr, 0, arr.length - 1);
}
function update(effect_id, array) {
document.getElementById(effect_id).innerHTML = "";
for (let i = 0; i < 10; i++) {
document.getElementById(effect_id).innerHTML += '<div class="label" style="height:' + array[i] + 'px;">' + array[i] + '</div>';
}
}
async function qs(array, left, right) {
let i = left;
let j = right;
let x = array[Math.floor((left + right) / 2)];
while (i <= j) {
await sleep(50);
while (array[i] < x && i < right) {
i++;
}
while (array[j] > x && j > left) {
j--;
}
if (i <= j) {
array.swap(i, j);
i++;
j--;
update("quicksort", arr);
}
}
if (left < j) {
await qs(array, left, j);
}
if (i < right) {
await qs(array, i, right);
}
}
window.onload = function() {
start_qs();
}
:root {
--main: #202020;
--sec: #D03737;
}
html {
background: var(--main);
color: var(--sec);
font-size: 28px;
}
body {
margin: 0;
padding: 0;
}
h3 {
text-align: center;
}
.element {
margin: auto;
width: 70%;
}
.effect {
width: 60%;
height: 200px;
margin: auto;
}
.label {
background: var(--sec);
width: 7%;
margin: 0 1.5%;
color: black;
text-align: center;
font-size: 0.75rem;
}
<script type="text/javascript" src="js/quickSort.js" /></script>
<h2 style="text-align:center;">Javascript algorithms</h2>
<div class="element" id="quicksorting">
<h3>Quick Sorting
<button style="border-radius:10px;padding:10px 30px;background:var(--main);border-color:var(--sec);color:var(--sec);" onclick="start_qs()">Restart</button></h3>
<div class="content" style="display:flex;">
<div class="effect" id="quicksort" style="display:flex;align-items:flex-end;">
</div>
</div>
</div>
I need help on the script for the counter to increment by one and have a animation of the incremented number, slide to top
something like that on the picture and this is what I have done so far.
.booking-wrapper .countdown-wrapper .countdown-container .order-list {
border: 5px solid #959595;
list-style-type: none;
padding-left: 0;
margin-bottom: 0;
overflow: hidden;
line-height: 1;
height: 56px;
margin-top: 8px;
}
.booking-wrapper .countdown-wrapper .countdown-container .order-list .order-list-item {
display: inline;
font-size: 40px;
font-weight: bold;
padding: 0 15px;
}
<div class="countdown-container">
<ul id="order-list" class="order-list">
<li class="order-list-item"><span>0</span></li>
<li class="order-list-item" style="border-left: 1px solid black;"><span>0</span></li>
<li class="order-list-item" style="border-left: 1px solid black; border-right: 1px solid black;"><span>8</span></li>
<li class="order-list-item"><span>1</span></li>
</ul>
</div>
You should probably use some existing library for that. But if you want to have your own implementation, then use the following elements:
Use CSS transitions, and in particular the transition property and the transitionend event.
Build the inner HTML dynamically, so that in the original HTML you only have the container element, which will initially be empty.
Let the HTML at the deepest level (for one digit) be 3 lines: on each line you put a digit. For example 8<br>9<br>0. They should form a sequence. Scroll the middle digit into view so that only that digit is visible. Perform the animation upward or downward as needed, and when the animation is complete, update the HTML and reset the scroll offset (which can be the top CSS property).
There is no need to have the span elements. Just put the content straight into the li elements.
Use promises, which make asynchronous code look better, certainly when using await
So here is how you could do it:
// Utility functions returning promises
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
const nextFrame = () => new Promise(resolve => requestAnimationFrame(resolve));
const animate = (elem, prop, value, duration) => {
return nextFrame().then(() => new Promise(resolve => {
elem.style.transition = `${prop} ${duration}ms`;
elem.style[prop] = `${value}px`;
const done = () => {
elem.style.transition = `${prop} 0ms`;
resolve();
}
elem.addEventListener("transitionend", done, {once: true});
})).then(nextFrame);
};
// DOM element wrapper for the counter functionality
class Counter {
constructor(element, length = 4, upwards = true) {
this.element = element;
this._value = 0;
this.upwards = !!upwards;
this.digits = Array.from({length}, () => element.appendChild(document.createElement("li")));
}
get value() {
return this._value;
}
set value(value) {
this._value = value;
const numStr = value.toString().padStart(4, "0").slice(-this.digits.length);
// Display the current number in the counter element (no animation)
this.digits.forEach( (digit, i) => {
// Put three lines, each having a digit, where the middle one is the current one:
digit.innerHTML = `${(+numStr[i]+(this.upwards ? 9 : 1))%10}<br>${numStr[i]}<br>${(+numStr[i]+(this.upwards ? 1 : 9))%10}`;
digit.style.top = `${-this.element.clientHeight}px`; // scroll the middle digit into view
});
}
async roll(direction = 1, duration = 500) {
await nextFrame();
const numChangingDigits = Math.min(this.digits.length,
this.value.toString().length - this.value.toString().search(direction > 0 ? /9*$/ : /0*$/) + 1);
const numStr = this.value.toString().padStart(4, "0").slice(-numChangingDigits);
const promises = this.digits.slice(-numChangingDigits).map((digit, i) =>
animate(digit, "top", (direction > 0) === this.upwards ? -this.element.clientHeight*2 : 0, duration)
);
await Promise.all(promises);
this.value = this.value + direction;
await nextFrame();
}
async rollTo(target, duration = 500, pause = 300) {
const direction = Math.sign(target - this.value);
while (this.value !== target) {
await this.roll(direction, duration);
await delay(pause);
}
}
}
// Demo:
const counter = new Counter(document.getElementById("order-list"), 4, true);
counter.value = 9931;
counter.rollTo(10002, 500, 300);
.order-list {
border: 5px solid #999;
list-style-type: none;
padding-left: 0;
overflow: hidden;
height: 50px;
line-height: 1;
display: inline-block;
}
.order-list > li {
display: inline-block;
font-size: 50px;
font-weight: bold;
padding: 0 15px;
border-left: 1px solid black;
position: relative;
top: 0;
}
.order-list > li:first-child {
border-left: 0;
}
<ul id="order-list" class="order-list"></ul>
There are some arguments you can use to modify the speed of the animations. There is also an argument that determines whether the dials roll upward or downward for getting the next digit.
I have this jquery functions. I want to make it just one function so I can get thesame results by just calling a function and passing some arguements.
As you can see, the function does basically the same thing counting numbers. I would love to just have one function , then parse out arguments to get the same results. something like startcount(arg1, arg2);
var one_countsArray = [2,4,6,7,4252];
var two_countsArray = [3,3,4,7,1229];
var sumemp = one_countsArray.reduce(add, 0);
var sumallis = two_countsArray.reduce(add, 0);
function add(a, b) {
return a + b;
}
var count = 0;
var inTv = setInterval(function(){startCount()},100);
var inTv2 = setInterval(function(){startCount2()},100);
function startCount()
{
if(count == sumemp) {
clearInterval(inTv);
} else {
count++;
}
$('.stats_em').text(count);
}
var count2 = 10;
function startCount2()
{
if(count2 == sumallis) {
clearInterval(inTv2);
} else {
count2++;
}
$('.stats_iss').text(count2);
}
div {
padding:50px 0;
background: #000000;
color: #ffffff;
width: 100px;
height:100px;
border-radius:50%;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<div class="stats_em"></div>
<div class="stats_iss"></div>
How about a very simple jquery plugin
$.fn.countTo = function(arrNums){
var self = this;
function add(a,b){
return a+b;
}
var current = 0;
var max = arrNums.reduce(add,0);
var int = setInterval(function(){
if(current == max)
clearInterval(int);
else
current++;
self.text(current);
},100);
return this;
}
$('.stats_em').countTo([2,4,6,7,4252]);
$('.stats_iss').countTo([3,3,4,7,1229]);
div {
padding:50px 0;
background: #000000;
color: #ffffff;
width: 100px;
height:100px;
border-radius:50%;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<div class="stats_em"></div>
<div class="stats_iss"></div>
When you notice you're rewriting chunks of similar code, moving to one generic function is the right approach! The best way to start is by trying to determine what you're parameters would be:
count and count2 show that you need a start count for your timer to start at
sumemp and sumpallis show that you need to be able to specify a maximum count
inTv and inTv show that you need to be able to set the interval
$('.stats_iss') and $('.stats_em') show that you need to be able to determine the output element
This means your final class, function or jquery extension will at least have a signature that resembles this:
function(startCount, maximumCount, interval, outputElement) { }
Once you've written this, you can paste in the code you already have. (I've replaced your setInterval with a setTimeout, other than that, not much changed)
var createCounter = function(start, max, interval, outputElement) {
var count = start;
var timeout;
var start = function() {
count += 1;
outputElement.text(count);
if (count < max) {
timeout = setTimeout(start, interval);
}
}
var stop = clearTimeout(timeout);
return {
start: start,
stop: stop
}
}
var one_countsArray = [2, 4, 6, 7, 300];
var two_countsArray = [3, 3, 4, 7, 100];
var sumemp = one_countsArray.reduce(add, 0);
var sumallis = two_countsArray.reduce(add, 0);
function add(a, b) {
return a + b;
}
var counters = [
createCounter(0, sumemp, 100, $('.stats_em')),
createCounter(10, sumallis, 100, $('.stats_iss'))
];
counters.forEach(function(counter) {
counter.start();
});
div {
padding: 50px 0;
background: #000000;
color: #ffffff;
width: 100px;
height: 100px;
border-radius: 50%;
text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
<div class="stats_em"></div>
<div class="stats_iss"></div>