javascript: get random pairs of an array without duplicates - javascript

I have an array of students, that should be random paired by clicking the button "button-newPairs". These pairs should be shown in 8 divs "pair one", "pair two", ... that contains two spans "studentOne" and "studentTwo".
I get the pairs in console but not by clicking the button "button-newPairs" and I don´t know how to change or insert the text content in my spans. Can someone help me, please? Thank you in advance.
var students = ['Al', 'Ma', 'Pu', 'Mi', 'Ma', 'Me', 'Ca', 'Na', 'Ja', 'Go', 'Ha', 'Fa', 'Ti', 'Fi' ];
var studentOne = document.querySelector('#student1');
var studentTwo = document.querySelector('#student2');
if (students.length % 2 != 0) {
alert("You must have an even number of students. You currently have " + students.length + " students.");
} else {
var arr1 = students.slice(),
arr2 = students.slice();
arr1.sort(function () { return 0.5 - Math.random(); });
arr2.sort(function () { return 0.5 - Math.random(); });
while (arr1.length) {
var student1 = arr1.pop(),
student2 = arr2[0] == student1 ? arr2.pop() : arr2.shift();
$(".button-newPairs").click(function () {
studentOne.textContent = student1;
studentTwo.textContent = student2;
});
console.log(student1 + ' works with ' + student2);
}
}
.container-pairs {
display: grid;
grid-template-columns: 150px 150px;
grid-gap: 20px;
justify-content: space-around;
align-content: center;
margin-bottom:20px;
}
.one {
grid-column: 1 / 2;
grid-row: 1;
}
.two {
grid-column: 2 / 2;
grid-row: 1;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div class="container-pairs">
<div class="pair one">
<span id="studentOne">NEW </span> <br>
<span id="studentTwo"> PAIRS</span>
</div>
<div class="pair two">
<span id="studentOne">NEW </span><br>
<span id="studentTwo"> PAIRS</span>
</div>
<div id="container-footer">
<div class="button-newPairs">
<span>NEW PAIRS</span>
</div>
</div>
</body>

I've commented inline. Look for the lines with a //
// Let's wrap this in a function so that we can call it with our button.
function makePairs() {
// We will clear our lists before each run of the function.
$('#studentOne').html('<h1>Student 1</h1>');
$('#studentTwo').html('<h1>Student 2</h1>');
var students = ['Al', 'Ma', 'Pu', 'Mi', 'Ma', 'Me', 'Ca', 'Na', 'Ja', 'Go', 'Ha', 'Fa', 'Ti', 'Fi'];
// By capturing these nodes in variables, we can reference them as our targets for insertion, below.
var studentOne = document.querySelector('#studentOne');
var studentTwo = document.querySelector('#studentTwo');
if (students.length % 2 != 0) {
alert("You must have an even number of students. You currently have " + students.length + " students.");
} else {
var arr1 = students.slice(),
arr2 = students.slice();
arr1.sort(function() {
return 0.5 - Math.random();
});
arr2.sort(function() {
return 0.5 - Math.random();
});
// Here we make a function that will insert a DOM fragment inside a target node
const insertFragment = (output, target) => {
let el;
let fragment = document.createDocumentFragment();
el = document.createElement('p');
el.innerText = output
fragment.appendChild(el);
target.appendChild(fragment);
}
while (arr1.length) {
var student1 = arr1.pop(),
student2 = arr2[0] == student1 ? arr2.pop() : arr2.shift();
// Here we use the function, sending student1 (the student) to studentOne (the target DOM node specified at the very top, #studentOne)
insertFragment(student1, studentOne)
insertFragment(student2, studentTwo)
console.log(student1 + ' works with ' + student2);
}
}
}
// Run the function on load
makePairs();
.container-pairs {
display: grid;
grid-template-columns: 150px 150px;
grid-gap: 20px;
justify-content: space-around;
align-content: center;
margin-bottom: 20px;
}
.one {
grid-column: 1 / 2;
grid-row: 1;
}
.two {
grid-column: 2 / 2;
grid-row: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div class="container-pairs">
<div id="studentOne">
<h1>Student 1</h1>
</div>
<div id="studentTwo">
<h1>Student 2</h1>
</div>
</div>
<div id="container-footer">
<button class="button-newPairs" onclick="makePairs()">
NEW PAIRS
</button>
</div>
</body>
The button tag, just above this line, has registered an event handler for clicks that will run the makePairs() function again.

I would use splice to remove the user from the array and loop through each user like so:
let students = ['Al', 'Ma', 'Pu', 'Mi', 'Ma', 'Me', 'Ca', 'Na', 'Ja', 'Go', 'Ha', 'Fa', 'Ti', 'Fi'];
while (students.length) {
let student1 = students.splice((Math.random() * 1000) % students.length, 1)
let student2 = students.splice((Math.random() * 1000) % students.length, 1)
console.log(`${student1} works with ${student2}`)
}

Related

How to create a CSS Grid Scheduler? Angular

How can I create a calendar with Angular where the first row is the places, the first column is the hours?
And the rest of the cells a space to put events.
For now I have this but I have the following problems,
-How can I add a border and the other thing is how do I place the rows of hours and places go hand in hand with the grid.
-My other problem is that the hours and places are dynamic when I create the grid template I have the values fixed.
HTML:
<div class="main-container">
<div class="stages-container-row">
<div>
<div *ngFor="let place of places">{{ place }}</div>
</div>
</div>
<div class="timing-container-column">
<div class="timings">
<div class="time">Time</div>
<div class="time" *ngFor="let hour of hours">
<span class="hour">
{{ hour }}
</span>
</div>
</div>
</div>
<ng-container *ngFor="let event of events">
<div class="slot" [ngStyle]="event.position">
<p>{{ event.location }}</p>
</div>
</ng-container>
CSS:
.main-container {
display: grid;
grid-template-columns: repeat(8, 1fr);
grid-template-rows: repeat(49, 1fr);
}
.stages-container-row {
grid-column: 2 / -1;
grid-row: 1 / 2;
}
[class^='stage']:nth-child(n + 2) {
grid-column: n + 2;
}
.details {
display: flex;
flex-direction: column;
}
.timing-container-column {
grid-column: 1 / 2;
grid-row: 1 / -1;
}
.timings {
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.time {
display: flex;
justify-content: center;
align-items: center;
}
.slot {
flex-direction: column;
border: 1px solid red;
}
TS:
export class AppComponent implements AfterViewInit, OnInit {
interval = 30;
hourInit = 0;
minuteInit = 0;
hourEnd = 24;
minuteEnd = 0;
hours = [];
places = ['P1', 'P2', 'P3', 'P4', 'P5', 'P6'];
events: any = [];
constructor() {}
ngOnInit(): void {
this.generateHours();
}
generateHours() {
const start = this.hourInit * 60 + this.minuteInit;
const end = this.hourEnd * 60;
const periods = [];
for (let i = start; i < end; i += this.interval) {
periods.push(i);
}
this.hours = periods.map((period) => {
let hour =
Math.floor(period / 60)
.toString()
.padStart(2, '0') +
':' +
(period % 60).toString().padStart(2, '0');
return hour;
});
}
ngAfterViewInit() {
this.createEvent(1, 4, 'P3');
this.createEvent(16, 3, 'P1');
}
createEvent(period: number, duration: number, location: string) {
const event: any = { period, duration, location };
event.position = this.calculateEventPosition(period, duration, location);
this.events.push(event);
}
calculateEventPosition(period: number, duration: number, location: string) {
let position = {};
// Calculate start time of event
let startIndex = period - 1;
let startRow = startIndex + 2;
// Calculate end time of event
let endIndex = startIndex + duration;
let endRow = endIndex + 1;
// Calculate location of event
let locationIndex = this.places.indexOf(location);
let locationColumn = locationIndex + 1;
// Set grid-row position of event
position['grid-row'] = startRow + ' / ' + endRow;
// Set grid-column position of event
position['grid-column'] = locationColumn + ' / ' + (locationColumn + 1);
return position;
}
}
I plan to achieve what is in the image, but I ran into these problems.

How to show "next" and "previous" buttons of a item in a array?

Im trying to use a array who contains 4 diferent maps.
The first element of the array must be "sticked" and change the current element of the array by clicking next.
The next button when it reaches to the last item of the array must be showed disabled.
The previous button is disabled and when the next is clicked it should be unabled.
Im pretty lost right now any suggestion or advice will be very welcomed
var i = 0;
var mapsArray = [
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d209569.44700750793!2d-56.380275318336025!3d-34.84309361411796!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x959f802b6753b221%3A0x3257eb39860f05a6!2sPalacio%20Salvo!5e0!3m2!1sen!2suy!4v1614269355326!5m2!1sen!2suy",
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d92110.09563909167!2d17.958933187703266!3d59.32686333113927!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x465f763119640bcb%3A0xa80d27d3679d7766!2sStockholm%2C%20Sweden!5e0!3m2!1sen!2suy!4v1614704350417!5m2!1sen!2suy",
"https://www.google.com/maps/embed?pb=!1m14!1m8!1m3!1d88989.45462143555!2d15.9390973!3d45.8128514!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x4765d701f8ef1d1d%3A0x312b512f1e7f6df9!2sCathedral%20of%20Zagreb!5e0!3m2!1sen!2suy!4v1614704668458!5m2!1sen!2suy",
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d6709.917127499258!2d-78.51409209928569!3d0.3576385746900253!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x8e2a5da2881494ab%3A0xae89047fc027c897!2sapuela%20imbabura%20intac!5e0!3m2!1sen!2suy!4v1614704741586!5m2!1sen!2suy"
];
document.getElementById('myIframe').src = mapsArray[Math.floor(Math.random() * mapsArray.length)];
const prevBtn = document.querySelector(".prev");
const nextBtn = document.querySelector(".next");
function nextBtn() {
i = i + 1;
i = i % mapsArray.length;
return mapsArray[i];
}
function prevBtn() {
if (i === 0) {
i = mapsArray.length;
}
i = i - 1;
return mapsArray[i]
}
.maps {
display: flex;
justify-content: center;
align-items: center;
}
#myIframe {
width: 600px;
height: 600px;
}
<div class="maps">
<iframe id='myIframe' class="maps-gallery active"></iframe>
</div>
<div class="btns">
<button disabled onclick="nextBtn()" class="btn prev">Prev</button>
<button onclick="prevBtn()" class="btn next">Next</button>
you can not have button name and function calling the same name hence the error in console.
save your iframe in variable and then do iFrame.src = mapsArray[i] inside both back and next functions.
Check the index numbers in functions and accordingly disable the buttons based on first/last/middle number of index array.
var i = 0;
var mapsArray = [
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d209569.44700750793!2d-56.380275318336025!3d-34.84309361411796!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x959f802b6753b221%3A0x3257eb39860f05a6!2sPalacio%20Salvo!5e0!3m2!1sen!2suy!4v1614269355326!5m2!1sen!2suy",
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d92110.09563909167!2d17.958933187703266!3d59.32686333113927!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x465f763119640bcb%3A0xa80d27d3679d7766!2sStockholm%2C%20Sweden!5e0!3m2!1sen!2suy!4v1614704350417!5m2!1sen!2suy",
"https://www.google.com/maps/embed?pb=!1m14!1m8!1m3!1d88989.45462143555!2d15.9390973!3d45.8128514!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x4765d701f8ef1d1d%3A0x312b512f1e7f6df9!2sCathedral%20of%20Zagreb!5e0!3m2!1sen!2suy!4v1614704668458!5m2!1sen!2suy",
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d6709.917127499258!2d-78.51409209928569!3d0.3576385746900253!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x8e2a5da2881494ab%3A0xae89047fc027c897!2sapuela%20imbabura%20intac!5e0!3m2!1sen!2suy!4v1614704741586!5m2!1sen!2suy"
];
let iFrame = document.getElementById('myIframe')
iFrame.src = mapsArray[Math.floor(Math.random() * mapsArray.length)];
const prevB = document.querySelector(".prev");
const nextB = document.querySelector(".next");
function nextBtn() {
console.clear()
if (i >= 0 && i < 3) {
iFrame.src = mapsArray[i]
prevB.disabled = false
console.log("next button array index set:" + i)
i++
} else {
iFrame.src = mapsArray[i]
nextB.disabled = true
console.log("next button array index set:" + i)
i++
}
}
function prevBtn() {
if (i === 0) {
i = mapsArray.length;
}
i = i - 1;
console.clear()
console.log("prev array index:" + i)
if (i <= 3 && i > 0) {
iFrame.src = mapsArray[i]
nextB.disabled = false
} else {
iFrame.src = mapsArray[i]
prevB.disabled = true
}
}
.maps {
display: flex;
justify-content: center;
align-items: center;
}
#myIframe {
width: 150px;
height: 150px;
}
<div class="maps">
<iframe id='myIframe' class="maps-gallery active"></iframe>
</div>
<div class="btns">
<button disabled onclick="prevBtn()" class="btn prev">Prev</button>
<button onclick="nextBtn()" class="btn next">Next</button>
</div>
This should work:
var mapsArray = [
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d209569.44700750793!2d-56.380275318336025!3d-34.84309361411796!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x959f802b6753b221%3A0x3257eb39860f05a6!2sPalacio%20Salvo!5e0!3m2!1sen!2suy!4v1614269355326!5m2!1sen!2suy",
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d92110.09563909167!2d17.958933187703266!3d59.32686333113927!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x465f763119640bcb%3A0xa80d27d3679d7766!2sStockholm%2C%20Sweden!5e0!3m2!1sen!2suy!4v1614704350417!5m2!1sen!2suy",
"https://www.google.com/maps/embed?pb=!1m14!1m8!1m3!1d88989.45462143555!2d15.9390973!3d45.8128514!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x4765d701f8ef1d1d%3A0x312b512f1e7f6df9!2sCathedral%20of%20Zagreb!5e0!3m2!1sen!2suy!4v1614704668458!5m2!1sen!2suy",
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d6709.917127499258!2d-78.51409209928569!3d0.3576385746900253!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x8e2a5da2881494ab%3A0xae89047fc027c897!2sapuela%20imbabura%20intac!5e0!3m2!1sen!2suy!4v1614704741586!5m2!1sen!2suy"
];
var i = Math.floor(Math.random() * mapsArray.length);
var iFrameElement = document.getElementById('myiFrame')
iFrameElement .src = mapsArray[i];
function nextBtn() {
if (i === mapsArray.length) i = 0;
else i += 1;
iFrameElement.src = mapsArray[i];
}
function prevBtn() {
if (i === 0) i = mapsArray.length;
else i -= 1;
iFrameElement.src = mapsArray[i];
}
.maps {
display: flex;
justify-content: center;
align-items: center;
}
#myiFrame {
width: 600px;
height: 600px;
}
<div class="maps">
<iframe id="myiFrame"></iframe>
</div>
<div class="btns">
<button onclick="nextBtn()">Prev</button>
<button onclick="prevBtn()">Next</button>
</div>
Here is a simple approach -->
var mapsArray = [
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d209569.44700750793!2d-56.380275318336025!3d-34.84309361411796!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x959f802b6753b221%3A0x3257eb39860f05a6!2sPalacio%20Salvo!5e0!3m2!1sen!2suy!4v1614269355326!5m2!1sen!2suy",
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d92110.09563909167!2d17.958933187703266!3d59.32686333113927!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x465f763119640bcb%3A0xa80d27d3679d7766!2sStockholm%2C%20Sweden!5e0!3m2!1sen!2suy!4v1614704350417!5m2!1sen!2suy",
"https://www.google.com/maps/embed?pb=!1m14!1m8!1m3!1d88989.45462143555!2d15.9390973!3d45.8128514!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x4765d701f8ef1d1d%3A0x312b512f1e7f6df9!2sCathedral%20of%20Zagreb!5e0!3m2!1sen!2suy!4v1614704668458!5m2!1sen!2suy",
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d6709.917127499258!2d-78.51409209928569!3d0.3576385746900253!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x8e2a5da2881494ab%3A0xae89047fc027c897!2sapuela%20imbabura%20intac!5e0!3m2!1sen!2suy!4v1614704741586!5m2!1sen!2suy"
];
var index = 0;
const _prevBtn = document.querySelector(".prev");
const _nextBtn = document.querySelector(".next");
update();
function update() {
document.getElementById('myIframe').src = mapsArray[index];
btnDisableCheck();
}
function nextBtn() {
if (index < mapsArray.length - 1) {
index++;
_prevBtn.disabled = false;
update();
}
}
function prevBtn() {
if (index > 0) {
index--;
_nextBtn.disabled = false;
update();
}
}
function btnDisableCheck() {
if (index == 0)
_prevBtn.disabled = true;
if (index == mapsArray.length - 1)
_nextBtn.disabled = true;
}
<iframe id='myIframe' class="maps-gallery active"></iframe>
<button onclick="prevBtn()" class="btn prev">Prev</button>
<button onclick="nextBtn()" class="btn next">Next</button>
I think this is what you want, but i had to change a few things:
var mapsArray = [
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d209569.44700750793!2d-56.380275318336025!3d-34.84309361411796!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x959f802b6753b221%3A0x3257eb39860f05a6!2sPalacio%20Salvo!5e0!3m2!1sen!2suy!4v1614269355326!5m2!1sen!2suy",
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d92110.09563909167!2d17.958933187703266!3d59.32686333113927!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x465f763119640bcb%3A0xa80d27d3679d7766!2sStockholm%2C%20Sweden!5e0!3m2!1sen!2suy!4v1614704350417!5m2!1sen!2suy",
"https://www.google.com/maps/embed?pb=!1m14!1m8!1m3!1d88989.45462143555!2d15.9390973!3d45.8128514!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x4765d701f8ef1d1d%3A0x312b512f1e7f6df9!2sCathedral%20of%20Zagreb!5e0!3m2!1sen!2suy!4v1614704668458!5m2!1sen!2suy",
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d6709.917127499258!2d-78.51409209928569!3d0.3576385746900253!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x8e2a5da2881494ab%3A0xae89047fc027c897!2sapuela%20imbabura%20intac!5e0!3m2!1sen!2suy!4v1614704741586!5m2!1sen!2suy"
];
var myIframe = document.getElementById('myIframe');
var prevButton = document.getElementById('prevBtn');
var nextButton = document.getElementById('nextBtn');
var i = Math.floor(Math.random() * mapsArray.length);
function update() {
myIframe.src = mapsArray[i];
if ( i == mapsArray.length - 1 ) {
prevButton.disabled = false;
nextButton.disabled = true;
}
else if ( i == 0 ) {
prevButton.disabled = true;
nextButton.disabled = false;
}
else {
prevButton.disabled = false;
nextButton.disabled = false;
}
}
function nextBtn() {
if ( i < mapsArray.length - 1 ) {
i++;
}
update();
}
function prevBtn() {
if (i > 0) {
i--;
}
update();
}
update();
.maps{
display: flex;
justify-content: center;
align-items: center;
}
#myIframe {
width: 600px;
height: 600px;
}
<div class ="maps">
<iframe id='myIframe' class="maps-gallery active"></iframe>
</div>
<div class="btns">
<button id="prevBtn" onclick="prevBtn()" class="btn prev">Prev</button>
<button id="nextBtn" onclick="nextBtn()" class= "btn next" >Next</button>
</div>
Here is a minimalist solution to your problem. The short style probably is not everybody's but it shows how little you need to write to actually reproduce the logic.
The core of the random sequencing of array elements is the shuffling of the array according to Fisher-Yates. After that I simply step through the shuffled array and enable/disable the buttons accordingly.
function shuffle(a,n){ // shuffle array a in place (Fisher-Yates)
let m=a.length;
n=n||m-1;
for(let i=0,j;i<n;i++){
j=Math.floor(Math.random()*(m-i)+i);
if (j-i) [ a[i],a[j] ] = [ a[j],a[i] ]; // swap 2 array elements
}; return a
}
const mapsArray = shuffle([
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d209569.44700750793!2d-56.380275318336025!3d-34.84309361411796!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x959f802b6753b221%3A0x3257eb39860f05a6!2sPalacio%20Salvo!5e0!3m2!1sen!2suy!4v1614269355326!5m2!1sen!2suy",
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d92110.09563909167!2d17.958933187703266!3d59.32686333113927!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x465f763119640bcb%3A0xa80d27d3679d7766!2sStockholm%2C%20Sweden!5e0!3m2!1sen!2suy!4v1614704350417!5m2!1sen!2suy",
"https://www.google.com/maps/embed?pb=!1m14!1m8!1m3!1d88989.45462143555!2d15.9390973!3d45.8128514!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x4765d701f8ef1d1d%3A0x312b512f1e7f6df9!2sCathedral%20of%20Zagreb!5e0!3m2!1sen!2suy!4v1614704668458!5m2!1sen!2suy",
"https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d6709.917127499258!2d-78.51409209928569!3d0.3576385746900253!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x8e2a5da2881 494ab%3A0xae89047fc027c897!2sapuela%20imbabura%20intac!5e0!3m2!1sen!2suy!4v1614704741586!5m2!1sen!2suy"]);
btns=document.querySelectorAll("button"), trgt=document.getElementById('myIframe');
trgt.src=mapsArray[0];
(i=>{
let n=mapsArray.length;
btns.forEach((b,k)=>b.onclick=()=>{
trgt.src=mapsArray[i=i+2*k-1];
btns[0].disabled=!i; btns[1].disabled=(i+1===n);
})
})(1); btns[0].click();
.maps {
display: flex;
justify-content: center;
align-items: center;
}
#myIframe {
width: 600px;
height: 600px;
}
<iframe id='myIframe' class="maps-gallery active"></iframe><br>
<button>Prev</button>
<button>Next</button>
The main function is embedded in an IIFE that encapsulates the current position index i and sets it to 0 as the starting value. The only "visible" global elements are the function shuffle() and the array mapsArray itself. For the actual stepping I apply a little trick: while in the .forEach() loop I use the index k to determine whether next(=1) or previous(=0) was clicked and then I calculate the increment accordingly.

CSS Text styling - fill text using animation with the numbers 1 and 0 - HTML

I am trying to do the following, however not sure if this possible/ how to go about doing it. Is it possible to do this animation in CSS styling.
The below is the HTML - I am trying to generate some animation to fill the following text with the numbers 1 and 0. I have managed to get some javascript going to create an animation for 1,0 but not sure how to fill 'DEVELOPER' with text to make up each letter.
var outputbinary = document.querySelector(".output");
var optionsarray = [0, 1];
var binaryarray = [];
setInterval(function() {
if (binaryarray.length <= 2000) {
var binarynumber = optionsarray[Math.floor(Math.random() * optionsarray.length)];
binaryarray.push(binarynumber);
var str = binaryarray.join(" ");
outputbinary.innerText = str;
}
}, 10);
<div class="output"></div>
<div class="loading">Developer</div>
<div>
I want the the text developer to be displayed like
111 0000
1 1 0
1 1 000
1 1 0
111 0000 //etc
This example builds letters from a series of zeros and ones, adds them to the page, and fades them in.
It displays them in a list. Each list item has a container that displays the sub-units using CSS grid.
const mapping = {
D: '1111010001100011000111110',
E: '1111110000111101000011111',
V: '1000110001100010101000100',
O: '0111010001100011000101110',
L: '1000010000100001000011111',
P: '1111010001111101000010000',
R: '1111010001111101000110001'
};
// Grab the binary mapping of the letter and
// return some HTML
function binaryise(letter) {
const arr = mapping[letter].split('');
return arr.map(char => `<div class="${char === '0' ? 'zero' : 'one'}">${char}</div>`).join('');
}
// For each letter in the word create a
// binary version and return it in a list-item container
function processWord(arr) {
const items = arr.map((letter, i) => {
const binaryised = binaryise(letter);
return `
<li data-id=${i}>
<div class="container">${binaryised}</div>
</li>
`;
}).join('');
return `<url>${items}</ul>`;
}
// Get a random number that hasn't previously appeared
function getRandom(arr, memo) {
const index = Math.floor(Math.random() * arr.length);
return memo.includes(index) ? getRandom(arr, memo) : index;
}
// Once the html has been added to the page
// (all set with opacity to 0)
// iterate over the letters turning the
// opacity of each to 1
function showLetters(arr, memo) {
memo = memo || [];
if (memo.length !== arr.length) {
const index = getRandom(arr, memo);
const letter = arr[index];
const el = document.querySelector(`[data-id="${index}"]`);
setTimeout(() => {
el.classList.add('show');
memo.push(index);
showLetters(arr, memo);
}, 1000);
}
}
var wordArr = 'Developer'.toUpperCase().split('');
// Process all the letters of the word and add them
// to the page...
const html = processWord(wordArr);
output.insertAdjacentHTML('beforeend', html);
// ...then fade them in
showLetters(wordArr);
ul {
width: 100%;
display: flex;
flex-direction: row;
list-style-type: none;
}
li {
display: inline-block;
margin-right: 1em;
opacity: 0;
}
.container {
width: 30px;
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
}
.show {
opacity: 1;
transition: opacity 4s linear;
}
.zero {
opacity: 0.2;
}
<div id="output"></div>

I want to display the ID of clicked Item in a class and delete it if clicked again

I am trying to make an interface where you can select tickets and buy them, I want that when I click on a seat it displays like "You are currently buying the next tickets + (The tickets chosen by the user)".
This is my code so far:
var seatsUnclicked = document.getElementsByClassName("seat-unique");
var seatsClicked = document.getElementsByClassName("seatClicked");
var images = document.getElementsByTagName("IMG");
var seatsOutput = document.getElementsById("seatsOutput");
var ticketsData = 0
for (let i = 0; i < seatsUnclicked.length; i++) {
seatsUnclicked[i].onmouseover = function() {
this.src = "chairclicked.svg";
this.onmouseout = function() {
this.src = "chair.svg"
}
if ($(this).hasClass('seatClicked')) {
this.src = "chairclicked.svg";
this.onmouseout = function() {
this.src = "chairclicked.svg"
}
}
}
seatsUnclicked[i].onclick = function() {
this.classList.add("new")
if ($(this).hasClass('seatClicked')) {
this.classList.remove("seatClicked")
this.classList.remove("new")
this.src = "chair.svg";
this.onmouseout = function() {
this.src = "chair.svg"
}
ticketsData = ticketsData - /* "the id of this element in a string" */
}
if ($(this).hasClass('new')) {
this.src = "chairclicked.svg";
this.classList.add("seatClicked")
this.classList.remove("new")
this.onmouseout = function() {
this.src = "chairclicked.svg"
}
ticketsData = ticketsData + /* "the ID of this element in a string" */
}
seatsOutput.innerHTML = "THE TICKETS YOU HAVE CHOSEN ARE" + string(ticketsData)
}
}
<div class="seats-row-A">
<img id="A1" class="seat-unique " src="http://via.placeholder.com/100x100?text=A1">
<img id="A2" class="seat-unique " src="http://via.placeholder.com/100x100?text=A2">
<img id="A3" class="seat-unique " src="http://via.placeholder.com/100x100?text=A3">
<img id="A4" class="seat-unique " src="http://via.placeholder.com/100x100?text=A4">
<img id="A5" class="seat-unique" src="http://via.placeholder.com/100x100?text=A5">
<img id="A6" class="seat-unique " src="http://via.placeholder.com/100x100?text=A6">
<img id="A7" class="seat-unique " src="http://via.placeholder.com/100x100?text=A7">
</div>
<h2 id="seatsOutput">Chosen Tickets:</h2>
jQuery
The only jQuery statement in OP code is: $(this).hasClass('seatClicked').
The plain JavaScript equivalent is: this.classList.contains('seatClicked').
Question
I couldn't follow the OP code because there was only a class, an id, and img tags that match the JavaScript, but it's not that clear because of the *.svg files (not provided.) Also, there's a curly bracket } missing (I think it belongs to the for loop, but I'm not wasting time on debugging typos.)
The Demo was built in mind with what the question and comments had mentioned:
"...I want that when I click on a seat it displays like "You are currently buying..."
Highlight icon when hovered over.
Reveal icon's id when hovered on.
All hover behavior is done with CSS: :hover, ::before, ::after, content: attr(id), content: '\a0\1f4ba'. Using JavaScript for behavior CSS can do will result in more CPU cycles. CSS will use GPU of your graphics card instead of the CPU.
Testing
The seats are dynamically generated with id="A* by entering a number in the input and clicking the View button. For each additional click of the button a new batch of seats are appended and have ids that correspond to it's group:
input: 55 and first click A0-A55,
input: 12 and second click B0-B12,
input: 222 and third click C0-C222
...
Last group is J
References
The Demo is basically a <form>. HTMLFormControlsCollection API is used to set/get form controls and values.
Reference the tag
const ui = document.forms.tickets;
This is a collection of all form controls in form#tickets
const t = ui.elements;
Now all form controls are now accessible by prefixing a form control's #id or [name] with the HTMLFormControlsCollection Object.
<textarea name='textA'></textarea>
Without HFCC API
var ta = document.querySelector('[name=textA]');
With HFCC API
var ta = t.textA;
The links are collected by Links Collection.
document.links
DocumentFragment is used to insert a huge amount of dynamic HTML in one shot efficiently and quickly.
document.createDocumentFragment();
Various array methods were used:
Array.from()
map()
fill()
indexOf()
Demo
const ui = document.forms.tickets;
const t = ui.elements;
const seats = document.getElementById('seats');
t.btn.addEventListener('click', seatsAvailable);
seats.addEventListener('click', function(e) {
let picked = [];
pickSeat(e, picked);
}, false);
function pickSeat(e, picked) {
const display = t.display;
if (e.target.tagName === "A") {
e.target.classList.toggle('picked');
picked = Array.from(document.querySelectorAll('.picked'));
}
picked = picked.map(function(seat, index, picked) {
return seat.id;
});
display.value = "";
display.value = picked;
}
function seatsAvailable(e) {
const qty = this.previousElementSibling;
const last = document.links[document.links.length - 1].id;
console.log(last);
const limit = parseInt(qty.value, 10) + 1;
const spots = new Array(limit);
spots.fill(0, 0, limit);
return generateSeats(spots, last);
}
function generateSeats(spots, last) {
if (last.charAt(0) === "J") {
t.display.textContent += "Last row available";
return false;
}
const rowID = ['x', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'];
let row = rowID.indexOf(last.charAt(0)) + 1;
const frag = document.createDocumentFragment();
const avSeats = spots.map(function(A, idx) {
const seat = document.createElement('a');
seat.id = rowID[row] + idx;
seat.href = "#/";
frag.appendChild(seat);
return seat;
});
seats.appendChild(frag);
if (document.links[0].id === 'x') {
const x = document.getElementById('x');
x.parentElement.removeChild(x);
}
if (document.links.length > 114) {
const ext = (Math.round(document.links.length / 114)*600)+600;
seats.style.maxHeight = ext+'px';
}
return avSeats;
}
html,
body {
width: 100%;
height: 10%;
font: 400 16px/1.3 Consolas;
}
#seats {
display: flex;
flex-flow: column wrap;
max-height: 600px;
width: auto;
border: 3px ridge grey;
}
.box {
display: table
}
input,
button,
label {
font: inherit
}
#qty {
text-align: right
}
#display {
display: table-cell;
}
.tag {
overflow-x: scroll;
overflow-y: hidden;
display: block;
width: 400px;
line-height: 1.3
}
a,
a:link,
a:visited {
display: inline-block;
margin: 0;
text-align: center;
text-decoration: none;
transition: all 500ms ease;
}
a:hover,
a:active {
background: rgba(0, 0, 0, 0);
color: #2468ac;
box-shadow: 0 0 0 3px #2468ac;
}
a::before {
content: attr(id);
color: transparent;
}
a:hover::before {
color: #2468ac;
}
a.picked::before {
color: #000;
}
a::after {
content: '\a0\1f4ba';
font-size: 1.5rem;
}
#x {
pointer-events: none
}
.as-console-wrapper {
width: 30%;
margin-left: 70%
}
<form id='tickets'>
<fieldset class='box'>
<legend>Available Seats</legend>
<fieldset class='box'>
<input id='qty' type='number' min='0' max='50' value='1'> <button id='btn' type='button'>View</button>
<label class='tag'>Current ticket purchases to seats:
<output id='display'></output>
</label>
</fieldset>
<section id='seats'>
<a id='x' href='#/'></a>
</section>
</fieldset>
</form>

Change calculator from pennies - js

I am working on a small app to improve my js skills. It is meant to allow the user to enter an amount of pennies, and from here the correct and minimum amount of change will be calculated to make this amount.
Currently I have the entry of pennies being worked out by the proper denominations (1p, 2p, 5p, 10p, 20p, 50p, £1, £2) however I am not sure how to get this to display the minimum change needed to make up the total number of pennies?
Below is my code so far, any help will be appreciated as I really want to learn how to do something this:
function calculate() {
var list = []
var x = document.getElementById("pennies").value;
resultTwoPounds = x / 200;
resultTwoPounds * 2;
list.push(Math.floor(resultTwoPounds));
resultPounds = x / 100;
list.push(Math.floor(resultPounds));
remaining = x % 100;
remainPennyFifty = Math.floor(remaining / 50);
list.push(remainPennyFifty);
remaining = x % 100;
remainPennyTwenty = Math.floor(remaining / 20);
list.push(remainPennyTwenty);
remaining = x % 100;
remainPennyTen = Math.floor(remaining / 10);
list.push(remainPennyTen);
remaining = x % 10;
list.push(Math.floor(remaining / 5));
remaining = x % 10;
list.push(Math.floor(remaining / 2));
remaining = x % 10;
list.push(Math.floor(remaining));
if (x > 0) {
resultLine = "You have <strong>" + x + " pennies</strong>, breakdown as follows: <br><br><strong>£2</strong> *" + list[0] + "<br><br><strong>" + "£1</strong> *" + list[1] + "<br><br><strong>50p</strong>" + " *" + list[2] + "<br><br><strong>20p</strong>" + " *" + list[3] + "<br><br><strong>10p</strong>" + " *" + list[4] + "<br><br><strong>5p</strong>" + " *" + list[5] + "<br><br><strong>2p</strong>" + " *" + list[6] + "<br><br><strong>1p</strong>" + " *" + list[7]
} else {
resultLine = "Please enter an amount"
}
document.getElementById('result').innerHTML = resultLine;
$("#submit").submit(function(e) {
e.preventDefault();
});
}
#pennies {
width: 6em;
vertical-align: middle;
}
#submit {
text-align: center;
}
.mainCalc {
text-align: center;
align-content: center;
}
.headings {
text-align: center;
color: white;
}
body {
margin-top: 200px;
background-color: lightblue;
}
#printResult {
text-align: center;
padding-top: 40px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="headings">
<h1>pennyCalc
<h1>
</div>
<!-- Start of form -->
<form onsubmit="return false">
<div class="mainCalc">
<br>
<strong>p:</strong>
<input type="number" placeholder=" Amount" step="1" min="0" id="pennies">
<br>
<button type="buttom" id="submit" onclick="calculate()">Calculate!</button>
<br>
</div>
</form>
<div id="printResult"><span id="result"></span></div>
A proposal
I have made a version of your calculator, let me show you how it works if you may.
The function works the same, the way I've organized it is different though. You don't need to use jQuery (as you haven't put the jQuery tag on this question).
Let us create a function divide that will return an array of the division integer result and the remainder of the euclidean division between x and y. For this, I will use, as you did, the % modulus operator and the Math.floor() function:
const divide = (x, y) => { return [ Math.floor(x/y), x % y ] };
I'm using the shorthand arrow function expression to declare it.
Then we will write the actual function calculate(): declare obj, the object that will contain are values and x, the money count. On each step we will decrease the value of x and append new properties to the object obj.
With our previous divide function this is pretty easy to do, you just have to write this line:
[ obj['twoPounds'], x ] = divide(x, 200);
By destructuring the array returned by divide(x, 200), we are assigning the division result to the property twoPounds of obj and assigning the remainder of the division to x.
The same result would have been met with:
let result = division(x, 200);
obj['twoPounds'] = result[0];
x = result[1]
But instead of calling the function twice you only do once, and the code is cleaner.
After calling divide for each coin type, x will have the value of 0 and obj will be filled with the number of coins per coin type.
Lastly, we can format our response with template literals with backticks (`) and the ${} syntax. This way we can embed JavaScript variables inside the string and also jump lines while writing the HTML markup in the editor.
For instance:
`You have ${obj.twoPounds} coins of £2`
Is the same as writing:
'You have' + obj.twoPounds + 'coins of £2'
JavaScript code and preview
const divide = (x, y) => { return [Math.floor(x / y), x % y] };
const calculate = function() {
let obj = {};
let x = document.querySelector('#pennies').value;
[ obj['twoPounds'], x ] = divide(x, 200);
[ obj['onePound'], x ] = divide(x, 100);
[ obj['fiftyPence'], x ] = divide(x, 50);
[ obj['twentyPence'], x ] = divide(x, 20);
[ obj['tenPence'], x ] = divide(x, 10);
[ obj['fivePence'], x ] = divide(x, 5);
[ obj['twoPence'], x ] = divide(x, 2);
[ obj['onePence'], x ] = divide(x, 1);
document.querySelector('#result').innerHTML = `
<div>
<span>You have: </span>
<span><strong>${obj.twoPounds}</strong> x £2, </span>
<span><strong>${obj.onePound}</strong> x £1, </span>
<span><strong>${obj.fiftyPence}</strong> x 50p, </span>
<span><strong>${obj.twentyPence}</strong> x 20p, </span>
<span><strong>${obj.tenPence}</strong> x 10p, </span>
<span><strong>${obj.fivePence}</strong> x 5p, </span>
<span><strong>${obj.twoPence}</strong> x 2p, </span>
<span><strong>${obj.onePence}</strong> x 1p, </span>
</div>
`;
return false;
}
Preview:
const divide = (x, y) => { return [ Math.floor(x / y), x % y ] };
const calculate = function() {
let obj = {};
let x = document.querySelector('#pennies').value;
[ obj['twoPounds'], x ] = divide(x, 200);
[ obj['onePound'], x ] = divide(x, 100);
[ obj['fiftyPence'], x ] = divide(x, 50);
[ obj['twentyPence'], x ] = divide(x, 20);
[ obj['tenPence'], x ] = divide(x, 10);
[ obj['fivePence'], x ] = divide(x, 5);
[ obj['twoPence'], x ] = divide(x, 2);
[ obj['onePence'], x ] = divide(x, 1);
document.querySelector('#result').innerHTML = `
<div>
<span>You have: </span>
<span><strong>${obj.twoPounds}</strong> x £2, </span>
<span><strong>${obj.onePound}</strong> x £1, </span>
<span><strong>${obj.fiftyPence}</strong> x 50p, </span>
<span><strong>${obj.twentyPence}</strong> x 20p, </span>
<span><strong>${obj.tenPence}</strong> x 10p, </span>
<span><strong>${obj.fivePence}</strong> x 5p, </span>
<span><strong>${obj.twoPence}</strong> x 2p, </span>
<span><strong>${obj.onePence}</strong> x 1p, </span>
</div>
`;
return false;
}
#pennies {
width: 6em;
vertical-align: middle;
}
#submit {
width: 10em;
text-align: center;
}
.mainCalc {
text-align: center;
align-content: center;
}
.headings {
text-align: center;
color: white;
}
body {
margin-top: 200px;
background-color: lightblue;
}
#printResult {
text-align: center;
padding-top: 40px;
}
<div class="headings">
<h1>Penny Calculator</h1>
</div>
<div class="mainCalc">
<input type="number" placeholder=" Amount" value="593" step="1" min="0" id="pennies">
<button type="buttom" id="submit" onclick="calculate()">Calculate!</button>
</div>
<div id="printResult"><span id="result"></span></div>
An even shorter version
I went ahead and refactored my own version, the actual function itself is very short indeed, enjoy!
Instead of having to call the function divide() multiple time, I have created an object containing the name, label and value in pennies for each coin.
let coins = [
{ name: 'twoPounds', label: '£2', value: 200 },
{ name: 'onePound', label: '£1', value: 100 },
{ name: 'fiftyPence', label: '50p', value: 50 },
{ name: 'twentyPence', label: '£2', value: 20 },
{ name: 'tenPence', label: '£2', value: 10 },
{ name: 'fivePence', label: '£2', value: 5 },
{ name: 'twoPence', label: '£2', value: 2 },
{ name: 'onePence', label: '£2', value: 1 }
];
Then in the function I use the .map method to go through each element of the coins array. The calculation of the number of coins in the formatting of the spans happens on the same line. The array returned by .map is then converted into a string with .join added in the element #result.
document.querySelector('#result').innerHTML = `
<div>
<span>You have: </span>
${ coins.map( coin => `<span>${([x, x] = divide(x, coin.value))[0]} x ${coin.label}</span>` ).join(', ') }
</div>
`
That's the line of code that does basically everything:
${ coins.map( coin => `<span>${([x, x] = divide(x, coin.value))[0]} x ${coin.label}</span>` ).join(', ') }
Here is the final code (same result as preview version):
const divide = (x, y) => { return [ Math.floor(x / y), x % y ] };
let coins = [
{ name: 'twoPounds', label: '£2', value: 200 },
{ name: 'onePound', label: '£1', value: 100 },
{ name: 'fiftyPence', label: '50p', value: 50 },
{ name: 'twentyPence', label: '£2', value: 20 },
{ name: 'tenPence', label: '£2', value: 10 },
{ name: 'fivePence', label: '£2', value: 5 },
{ name: 'twoPence', label: '£2', value: 2 },
{ name: 'onePence', label: '£2', value: 1 }
];
const calculate = function() {
let x = document.querySelector('#pennies').value;
document.querySelector('#result').innerHTML = `
<div>
<span>You have: </span>
${ coins.map( coin => `<span>${([x, x] = divide(x, coin.value))[0]} x ${coin.label}</span>` ).join(', ') }
</div>
`
return false;
}
#pennies {
width: 6em;
vertical-align: middle;
}
#submit {
width: 10em;
text-align: center;
}
.mainCalc {
text-align: center;
align-content: center;
}
.headings {
text-align: center;
color: white;
}
body {
margin-top: 200px;
background-color: lightblue;
}
#printResult {
text-align: center;
padding-top: 40px;
}
<div class="headings">
<h1>Penny Calculator</h1>
</div>
<div class="mainCalc">
<input type="number" placeholder=" Amount" value="593" step="1" min="0" id="pennies">
<button type="buttom" id="submit" onclick="calculate()">Calculate!</button>
</div>
<div id="printResult"><span id="result"></span></div>

Categories

Resources