Calculator display - javascript

If you calculate (45 - 5), the calculator will return 40 but if you click on the 5 it will concatenate 40 and 5 and it will make '405', I wanted the calculator to clear the display when I press the 5 to start a new operation so that the user doesn't have to manually clear the calculator with AC, I know I need to program a method that checks if an operation has been completed or not but I can't get it to work, can you help me? what I need to do? what code do i need to write to make this work? my github: https://github.com/JackHeroes/Calculator
class CalcController{
constructor(){
this._timeEl = document.querySelector('#time');
this._dateEl = document.querySelector('#date');
this._historicEl = document.querySelector('#historic');
this._displayCalcEl = document.querySelector('#display');
this._audio = new Audio('/audio/click.wav');
this._audioOnOff = false;
this._currentDate;
this._locale = 'pt-BR';
this._operation = [];
this._readyToClear = false;
this._lastNumber = '';
this._lastOperator = '';
this.initialize();
this.initButtonsEvents();
this.initKeyboard();
}
initialize(){
this.playAudio(true);
this.setDisplayDateTime();
setInterval(() =>{
this.setDisplayDateTime();
}, 1000);
this.setLastNumberToDisplay();
document.querySelector('#audio').addEventListener('click', e =>{
this.toggleAudio();
})
let icon = document.querySelector('#audio');
icon.addEventListener('click', e =>{
if(icon.classList.contains('bi-volume-up-fill')){
icon.classList.remove('bi-volume-up-fill');
icon.classList.add('bi-volume-mute-fill');
} else{
icon.classList.remove('bi-volume-mute-fill');
icon.classList.add('bi-volume-up-fill');
}
});
}
toggleAudio(){
this._audioOnOff = !this._audioOnOff;
}
playAudio(){
if(this._audioOnOff){
this._audio.currentTime = 0;
this._audio.play();
}
}
initKeyboard(){
document.addEventListener('keyup' , e =>{
this.playAudio();
switch(e.key){
case 'Escape':
this.clearAll();
break;
case 'Backspace':
this.clearEntry();
break;
case '+':
case '-':
case '*':
case '/':
this.addOperation(e.key);
break;
case 'Enter':
case '=':
this.calc();
break;
case ',':
case '.':
this.addDot();
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
this.addOperation(parseInt(e.key));
break;
}
});
}
setDisplayDateTime(){
this.displayTime = this.currentDate.toLocaleTimeString(this._locale)
this.displayDate = this.currentDate.toLocaleDateString(this._locale, {day: '2-digit', month: 'long', year: 'numeric'})
}
setLastNumberToDisplay(){
let lastNumber = this.getLastItem(false);
if(!lastNumber) lastNumber = [0];
this.displayCalc = lastNumber;
}
addEventListenerAll(element, events, fn){
events.split(' ').forEach(event =>{
element.addEventListener(event, fn, false);
});
}
clearAll(value){
let alreadyCalled = false;
if (!alreadyCalled) {
this._operation = [];
this._lastNumber = '';
this._lastOperator = '';
this.setLastNumberToDisplay();
if(value) this.addOperation(value);
this._readyToClear = false;
alreadyCalled = true;
}
}
clearEntry(){
this._operation.pop();
this.setLastNumberToDisplay();
}
ClearLast(){
}
getLastOperation(){
return this._operation[this._operation.length-1];
}
setLastOperation(value){
this._operation[this._operation.length-1] = value;
}
isOperator(value){
return (['+','-','*','/'].indexOf(value) > -1);
}
pushOperation(value){
this._operation.push(value);
if(this._operation.length > 3){
this.calc();
}
}
addOperation(value){
if(isNaN(this.getLastOperation())){
if(this.isOperator(value)){
this.setLastOperation(value);
} else{
this.pushOperation(value);
this.setLastNumberToDisplay();
}
} else{
if(this.isOperator(value)){
this.pushOperation(value);
} else{
let newValue;
if(this.getLastOperation().toString() !== '0'){
newValue = this.getLastOperation().toString() + value.toString();
} else{
newValue = value.toString();
}
this.setLastOperation(newValue);
this.setLastNumberToDisplay();
}
}
if (this._readyToClear){
this.clearAll(value);
this._readyToClear = false;
return
}
}
addDot(){
let lastOperation = this.getLastOperation();
if(typeof lastOperation === 'string' && lastOperation.split('').indexOf('.') > -1) return;
if(this.isOperator(lastOperation) || lastOperation === undefined){
this.pushOperation('0.');
} else{
this.setLastOperation(lastOperation.toString() + '.');
}
this.setLastNumberToDisplay();
}
getResult(){
return eval(this._operation.join(''));
}
getLastItem(isOperator = true){
let lastItem;
for(let i = this._operation.length - 1; i >= 0; i--){
if(this.isOperator(this._operation[i]) == isOperator){
lastItem = this._operation[i];
break;
}
}
if(lastItem == 0){
return lastItem;
} else if(!lastItem){
lastItem = (isOperator) ? this._lastOperator : this._lastNumber;
}
return lastItem;
}
calc() {
let last = '';
this._lastOperator = this.getLastItem();
if (this._operation.length < 3) {
let firstItem = this._operation[0];
this._operation = [firstItem, this._lastOperator, this._lastNumber];
} else if (this._operation.length > 3) {
last = this._operation.pop();
this._lastNumber = this.getResult();
} else if (this._operation.length == 3) {
this._lastNumber = this.getLastItem(false);
}
let result = this.getResult();
this._operation = [result];
if (last) this._operation.push(last);
this.setLastNumberToDisplay();
}
setError(){
this.displayCalc = 'Erro';
}
execBtn(value){
this.playAudio();
switch(value){
case 'ac':
this.clearAll();
break;
case 'ce':
this.clearEntry();
break;
case 'cl':
this.ClearLast();
break;
case 'division':
this._readyToClear = false;
this.addOperation('/');
break;
case 'multiplication':
this._readyToClear = false;
this.addOperation('*');
break;
case 'subtraction':
this._readyToClear = false;
this.addOperation('-');
break;
case 'addition':
this._readyToClear = false;
this.addOperation('+');
break;
case 'dot':
this.addDot();
break;
case 'equal':
this.calc();
this._readyToClear = true;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
this.addOperation(parseInt(value));
break;
default:
this.setError();
break;
}
}
initButtonsEvents(){
let buttons = document.querySelectorAll('#buttons > section > button');
buttons.forEach((btn, index) =>{
this.addEventListenerAll(btn, 'click drag', e =>{
let textBtn = btn.className.replace('btn-', '');
this.execBtn(textBtn);
});
});
}
get displayTime(){
return this._timeEl.innerHTML;
}
set displayTime(value){
return this._timeEl.innerHTML = value;
}
get displayDate(){
return this._dateEl.innerHTML
}
set displayDate(value){
return this._dateEl.innerHTML = value
}
get displayHistoric(){
return this._historicEl.innerHTML
}
set displayHistoric(value){
return this._historicEl.innerHTML = value
}
get displayCalc(){
return this._displayCalcEl.innerHTML;
}
set displayCalc(value){
if (value.toString().length > 10){
this.setError();
return false;
}
this._displayCalcEl.innerHTML = value;
}
get currentDate(){
return new Date();
}
set currentDate(value){
this._currentDate = value;
}
}
window.calculator = new CalcController;
#font-face {
font-family: 'Digital-7';
src: url('/font/digital-7.ttf');
}
#calculator-container {
height: 100vh;
width: 100vh;
}
#calculator {
background-color: #B5ACEA;
border-radius: .5rem;
box-shadow: 0px 10px 0px 0px #8468EC;
width: fit-content;
}
#audio {
color: #F5F5F5;
cursor: pointer;
font-size: 2rem;
}
#display-container {
background-color: #3D2C8D;
border-radius: .5rem;
box-shadow: inset 0px 5px 0px 0px #1C0C5B;
font-family: 'Digital-7', sans-serif;
height: fit-content;
}
#time,
#date,
#historic,
#display {
color: #F5F5F5;
}
#historic {
height: 1rem;
}
#display {
font-size: 3rem;
height: 4rem;
}
#buttons button {
background-color: #3D2C8D;
border-radius: .5rem;
box-shadow: 0px 5px 0px 0px #1C0C5B;
color: #F5F5F5;
font-size: 1.5rem;
height: 5rem;
margin-bottom: .5rem;
margin-top: .5rem;
transition-duration: 1s, .1s;
transition-property: background-color, transform;
transition-timing-function: ease;
width: 5rem;
}
#buttons button:hover {
background-color: #1C0C5B;
}
#buttons button:active {
transform: translateY(5px);
}
#buttons .btn-ac,
#buttons .btn-ce,
#buttons .btn-cl,
#buttons .btn-equal {
background-color: #8468EC;
}
#buttons .btn-equal {
flex-grow: 2;
}
<!DOCTYPE html>
<html lang="pt-br">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Calculator</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.3.0-alpha1/dist/js/bootstrap.bundle.min.js" integrity="sha384-w76AqPfDkMBDXo30jS1Sgez6pr3x5MlQ1ZAGC+nuZB+EYdgRZgiwxhTBTkF7CXvN" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons#1.10.3/font/bootstrap-icons.css">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container-fluid d-flex justify-content-center align-items-center" id="calculator-container">
<div class="container-fluid p-4" id="calculator">
<section class="mb-2">
<i class="bi bi-volume-up-fill" id="audio"></i>
</section>
<section class="display mb-2" id="display-container">
<div class="d-flex justify-content-between ps-2 pe-2 pt-2">
<p class="m-0" id="time"></p>
<p class="m-0" id="date"></p>
</div>
<div class="d-flex justify-content-end ps-2 pe-2">
<p class="m-0" id="historic"></p>
</div>
<div class="d-flex justify-content-end ps-2 pe-2 pb-2">
<p class="m-0" id="display">0</p>
</div>
</section>
<div id="buttons">
<section class="d-flex gap-2">
<button class="btn-ac">AC</button>
<button class="btn-ce">CE</button>
<button class="btn-cl"><i class="bi bi-x-octagon"></i></button>
<button class="btn-division">÷</button>
</section>
<section class="d-flex gap-2">
<button class="btn-7">7</button>
<button class="btn-8">8</button>
<button class="btn-9">9</button>
<button class="btn-multiplication">x</button>
</section>
<section class="d-flex gap-2">
<button class="btn-4">4</button>
<button class="btn-5">5</button>
<button class="btn-6">6</button>
<button class="btn-subtraction">-</button>
</section>
<section class="d-flex gap-2">
<button class="btn-1">1</button>
<button class="btn-2">2</button>
<button class="btn-3">3</button>
<button class="btn-addition">+</button>
</section>
<section class="d-flex gap-2">
<button class="btn-0">0</button>
<button class="btn-dot">.</button>
<button class="btn-equal">=</button>
</section>
</div>
</div>
</div>
<script src="/js/controller/CalcController.js"></script>
<script src="/js/calculator.js"></script>
</body>
</html>

Your code needs some additional state (by this I mean data or information) so that it knows if it should clear the display when a new button is pressed. A simple boolean variable would suffice such as shouldClear which the code sets to true when you press equals and back to false again after pressing any other button and clearing the display.

Related

Can a function be inside another function?

I am working on a library project but my function called changeColor inside the readStatus function does not appear to be working.
I've tried separating it but having two event listeners on the same button does not appear to work. My goal is for readStatus function to allow a user to update the status of a book from no to yes when finished with the book.
Likewise, I want to change the background color of the div (class: card) when yes to be green and no to be red.
Can anyone tell me what I'm doing wrong?
let myLibrary = [];
function Book(title, author, pages, read) {
this.title = title;
this.author = author;
this.pages = pages;
this.read = read;
}
function addBookToLibrary(title, author, pages, read) {
let book = new Book(title, author, pages, read);
myLibrary.push(book);
displayOnPage();
}
function displayOnPage() {
const books = document.querySelector(".books");
const removeDivs = document.querySelectorAll(".card");
for (let i = 0; i < removeDivs.length; i++) {
removeDivs[i].remove();
}
let index = 0;
myLibrary.forEach((myLibrarys) => {
let card = document.createElement("div");
card.classList.add("card");
books.appendChild(card);
for (let key in myLibrarys) {
let para = document.createElement("p");
para.textContent = `${key}: ${myLibrarys[key]}`;
card.appendChild(para);
}
let read_button = document.createElement("button");
read_button.classList.add("read_button");
read_button.textContent = "Read ";
read_button.dataset.linkedArray = index;
card.appendChild(read_button);
read_button.addEventListener("click", readStatus);
let delete_button = document.createElement("button");
delete_button.classList.add("delete_button");
delete_button.textContent = "Remove";
delete_button.dataset.linkedArray = index;
card.appendChild(delete_button);
delete_button.addEventListener("click", removeFromLibrary);
function removeFromLibrary() {
let retrieveBookToRemove = delete_button.dataset.linkedArray;
myLibrary.splice(parseInt(retrieveBookToRemove), 1);
card.remove();
displayOnPage();
}
function readStatus() {
let retrieveBookToToggle = read_button.dataset.linkedArray;
Book.prototype = Object.create(Book.prototype);
const toggleBook = new Book();
if (myLibrary[parseInt(retrieveBookToToggle)].read == "yes") {
toggleBook.read = "no";
myLibrary[parseInt(retrieveBookToToggle)].read = toggleBook.read;
} else if (myLibrary[parseInt(retrieveBookToToggle)].read == "no") {
toggleBook.read = "yes";
myLibrary[parseInt(retrieveBookToToggle)].read = toggleBook.read;
}
let colorDiv = document.querySelector(".card");
function changeColor() {
for (let i = 0; i < length.myLibrary; i++) {
if (myLibrary[i].read == "yes") {
colorDiv.style.backgroundColor = "green";
} else if (myLibrary[i].read == "no") {
colorDiv.style.backgroundColor = "red";
}
}
}
displayOnPage();
}
index++;
});
}
let add_book = document.querySelector(".add-book");
add_book.addEventListener("click", popUpForm);
function popUpForm() {
document.getElementById("data-form").style.display = "block";
}
function closeForm() {
document.getElementById("data-form").style.display = "none";
}
let close_form_button = document.querySelector("#close-form");
close_form_button.addEventListener("click", closeForm);
function intakeFormData() {
let title = document.getElementById("title").value;
let author = document.getElementById("author").value;
let pages = document.getElementById("pages").value;
let read = document.getElementById("read").value;
if (title == "" || author == "" || pages == "" || read == "") {
return;
}
addBookToLibrary(title, author, pages, read);
document.getElementById("data-form").reset();
}
let submit_form = document.querySelector("#submit-form");
submit_form.addEventListener("click", function (event) {
event.preventDefault();
intakeFormData();
});
* {
margin: 0;
padding: 0;
background-color: rgb(245, 227, 205);
}
.books {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
text-align: center;
margin: 20px;
gap: 10px;
}
.card {
border: 1px solid black;
border-radius: 15px;
padding: 10px;
}
.forms {
display: flex;
flex-direction: column;
align-items: center;
}
form {
margin-top: 20px;
}
select,
input[type="text"],
input[type="number"] {
width: 100%;
box-sizing: border-box;
}
.buttons-container {
display: flex;
margin-top: 10px;
}
.buttons-container button {
width: 100%;
margin: 2px;
}
.add-book {
margin-top: 20px;
}
#data-form {
display: none;
}
.read_button {
margin-right: 10px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="style.css" />
<title>Document</title>
</head>
<body>
<div class="container">
<div class="forms">
<button class="add-book">Add Book To Library</button>
<div class="pop-up">
<form id="data-form">
<div class="form-container">
<label for="title">Title</label>
<input type="text" name="title" id="title" />
</div>
<div class="form-container">
<label for="author">Author</label>
<input type="text" name="author" id="author" />
</div>
<div class="form-container">
<label for="pages">Pages</label>
<input type="number" name="pages" id="pages" />
</div>
<div class="form-container">
<label for="read">Read</label>
<select name="read" id="read">
<option value="yes">Yes</option>
<option value="no">No</option>
</select>
</div>
<div class="buttons-container">
<button type="submit" id="submit-form">Submit Form</button>
<button type="button" id="close-form">Close Form</button>
</div>
</form>
</div>
</div>
<div class="books"></div>
</div>
<script src="script.js"></script>
</body>
</html>
A couple things needed.
First, you should put the readStatus and removeFromLibrary functions outside of the foreach loop.
Then I think you are wanting changeColor to run whenever readStatus is run. Either put the changeColor code directly inside the readStatus or put changeColor() inside readStatus.
I think you want the Book to not be a function but a class.

Button array is empty after I copied from another array that has the whole set of HTMLCollection

I want to store all the existing button names into an array(copyAllButtons) by using the push function.
However, after the for-loop, there is still nothing inside copyAllButtons.
I am trying to make a reset function that required the array(copyAllButtons) to restore all the button names saved.
Can anyone help me? Thank you.
var all_buttons = document.getElementsByTagName('button'); //all button names are saved
var copyAllButtons = [];
console.log(all_buttons);
for (let i = 0; i < all_buttons.length; i++) {
copyAllButtons.push(all_buttons[i].classList[1]);
}
console.log(copyAllButtons); //####Button array is empty####
This is my file:
https://drive.google.com/file/d/1qbAAHClxJhNQUFyvrSklbGwX9tbsEsL8/view?usp=sharing
message of console.log(copyAllButtons)
element inside all_buttons
code related:JS
//challenge4
var all_buttons = document.getElementsByTagName('button'); //all button names are saved
var copyAllButtons = [];
console.log(all_buttons);
for (let i = 0; i < all_buttons.length; i++) {
copyAllButtons.push(all_buttons[i].classList[1]);
}
console.log(copyAllButtons); //####Button array is empty####
function buttonColorChange(buttonThingy) {
if (buttonThingy.value === 'red') {
buttonsRed();
} else if (buttonThingy.value === 'green') {
buttonsGreen();
} else if (buttonThingy.value === 'reset') {
buttonsColorReset();
} else if (buttonThingy.value === 'random') {
randomColors();
}
}
function buttonsRed() {
for (let i = 0; i < all_buttons.length; i++) {
all_buttons[i].className = 'btn btn-danger';
}
}
function buttonsGreen() {
for (let i = 0; i < all_buttons.length; i++) {
all_buttons[i].className = 'btn btn-success';
}
}
function buttonsColorReset() { //##function that i am working on##
for (let i = 0; i < all_buttons.length; i++) {
all_buttons[i].classList.remove(all_buttons[i].classList[1]);
all_buttons[i].classList.add(copyAllButtons[i]);
}
}
function randomColors() {
for (let i = 0; i < all_buttons.length; i++) {
var x = Math.floor(Math.random() * 4);
var y = ['btn-primary', 'btn-danger', 'btn-warning', 'btn-success'];
all_buttons[i].className = 'btn ' + y[x];
}
}
HTML
<div class="container-4">
<h2 id="change-my-color">Challenge 4:Change the color of all buttons</h2>
<div class="flex-box-pick-color">
<form action="">
<select name="backdrop" id="background" onChange="buttonColorChange(this)">
<option value="random">Random</option>
<option value="red">Red</option>
<option value="green">Green</option>
<option value="reset">Reset</option>
</select>
</form>
<button class="btn btn-primary">Wee!</button>
<button class="btn btn-danger">Yahoo!</button>
<button class="btn btn-warning">Google!</button>
<button class="btn btn-success">Facebook!</button>
</div>
</div>
CSS:
.container-1, .container-2 , .container-3 ,.container-4{
border: 1px solid blue;
width:75%;
margin: 0 auto;
text-align: center;
}
.flex-box-container-1, .flex-box-container-2,.flex-box-rps,.flex-box-pick-color{
display:flex;
border:1px solid purple;
padding: 10px;
flex-wrap:wrap;
flex-direction: row;
justify-content: space-around;
}
All my code for reference:
javascript:
function ageInDays() {
var birthYear = prompt("What year were you born?")
var days = (2021 - birthYear) * 365
var h1 = document.createElement('h1')
var textAnswer = document.createTextNode('You are ' + days + ' days old')
h1.setAttribute('id', 'days');
h1.appendChild(textAnswer)
document.getElementById('flex-box-result').appendChild(h1)
}
function reset() {
document.getElementById('days').remove()
}
function generateCat() {
var image = document.createElement('img');
var div = document.getElementById('flex-cat-gen');
image.src = "https://thecatapi.com/api/images/get?format=src&type=gif&size=small";
div.appendChild(image);
}
//challenge3 rock paper scissors
function getRandomInt(max) {
return Math.floor(Math.random() * max);
}
function randToRpsInt() {
return Math.floor(Math.random() * 3);
}
function numberToChoice(number) {
return ['rock', 'paper', 'scissors'][number]
}
function rpsGame(yourChoice) {
var result;
console.log(yourChoice.id);
var humanChoice, botChoice;
var message
humanChoice = yourChoice.id;
botChoice = numberToChoice(randToRpsInt());
console.log(botChoice);
if (humanChoice === 'rock') {
if (botChoice === 'rock') {
result = "tie"
console.log("tie");
}
else if (botChoice === 'paper') {
result = "lost"
console.log("You Lost>_<");
}
else {
result = "win"
console.log("You Win OAO");
}
}
else if (humanChoice === 'paper') {
if (botChoice === 'rock') {
result = "win";
console.log("You Win OAO");
}
else if (botChoice === 'scissors') {
result = "lost";
console.log("You Lost>_<");
}
else {
result = "tie";
console.log("tie");
}
}
//scissors
else {
if (botChoice === 'paper') {
result = "win";
console.log("You Win OAO");
}
else if (botChoice === 'rock') {
result = "lost";
console.log("You Lost>_<");
}
else {
result = "tie";
console.log("tie");
}
}
message = finalMessage(result);
rpsFrontEnd(humanChoice, botChoice, message);
}
function finalMessage(result) {
if (result === "lost")
return { 'message': 'You lost!', 'color': 'red' };
else if (result === "win")
return { 'message': 'You won!', 'color': 'green' };
else
return { 'message': 'You tied!', 'color': 'yellow' };
}
function rpsFrontEnd(humanImageChoice, botImageChoice, finalMessage) {
var imagesDatabase = {
'rock': document.getElementById('rock').src,
'paper': document.getElementById('paper').src,
'scissors': document.getElementById('scissors').src
}
document.getElementById('rock').remove();
document.getElementById('paper').remove();
document.getElementById('scissors').remove();
var humanDiv = document.createElement('div');
var botDiv = document.createElement('div');
var messageDiv = document.createElement('div');
humanDiv.innerHTML = "<img src='" + imagesDatabase[humanImageChoice] + "' height=150 width=150 style='box-shadow: 0px 10px 50px rgba(37,50,233,1);'>"
botDiv.innerHTML = "<img src='" + imagesDatabase[botImageChoice] + "' height=150 width=150 style='box-shadow: 0px 10px 50px rgba(3243,38,24,1);'>"
messageDiv.innerHTML = "<h1 style='color: " + finalMessage['color'] + "; font-size: 60px;padding:30px; '>" + finalMessage['message'] + "</h1>"
document.getElementById('flex-box-rps-div').appendChild(humanDiv);
document.getElementById('flex-box-rps-div').appendChild(messageDiv);
document.getElementById('flex-box-rps-div').appendChild(botDiv);
}
//challenge4
var all_buttons = document.getElementsByTagName('button'); //all button names are saved
var copyAllButtons = [];
console.log(all_buttons);
for (let i = 0; i < all_buttons.length; i++) {
copyAllButtons.push(all_buttons[i].classList[1]);
}
console.log(copyAllButtons); //####Button array is empty####
function buttonColorChange(buttonThingy) {
if (buttonThingy.value === 'red') {
buttonsRed();
} else if (buttonThingy.value === 'green') {
buttonsGreen();
} else if (buttonThingy.value === 'reset') {
buttonsColorReset();
} else if (buttonThingy.value === 'random') {
randomColors();
}
}
function buttonsRed() {
for (let i = 0; i < all_buttons.length; i++) {
all_buttons[i].className = 'btn btn-danger';
}
}
function buttonsGreen() {
for (let i = 0; i < all_buttons.length; i++) {
all_buttons[i].className = 'btn btn-success';
}
}
function buttonsColorReset() { //##function that i am working on##
for (let i = 0; i < all_buttons.length; i++) {
all_buttons[i].classList.remove(all_buttons[i].classList[1]);
all_buttons[i].classList.add(copyAllButtons[i]);
}
}
function randomColors() {
for (let i = 0; i < all_buttons.length; i++) {
var x = Math.floor(Math.random() * 4);
var y = ['btn-primary', 'btn-danger', 'btn-warning', 'btn-success'];
all_buttons[i].className = 'btn ' + y[x];
}
}
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="style.css">
<title>challenge game</title>
</head>
<body>
<script src="home.js"></script>
<div class="container-1">
<h2>Challenge 1: Your Age in Days</h2>
<div class="flex-box-container-1">
<div> <button class="btn btn-primary" onclick="ageInDays()">Click Me</button></div>
<div> <button class="btn btn-danger" onclick="reset()">Reset</button></div>
</div>
</div>
<div class="flex-box-container-1">
<div id="flex-box-result">
</div>
</div>
<div class="container-2">
<h2>Challenge 2: Cat Generator</h2>
<button class="btn btn-success" id="cat-generator" onClick="generateCat()">Generate Cat</button>
<div class="flex-box-container-2" id="flex-cat-gen">
</div>
</div>
<div class="container-3">
<h2>Challenge 3:Rock,Paper,Scissors</h2>
<div class="flex-box-rps" id="flex-box-rps-div">
<img id="rock" src="https://cdn.drawception.com/images/panels/2017/2-4/wqmCPbxybn-4.png" alt=""
onClick="rpsGame(this)" width="250" height="250">
<img id="paper" src="https://sc04.alicdn.com/kf/UTB8apntp0nJXKJkSaiyq6AhwXXaR.jpg" alt="" onClick="rpsGame(this)"
width="250" height="250">
<img id="scissors" src="https://www.collinsdictionary.com/images/full/scissors_100136453.jpg" alt=""
onClick="rpsGame(this)" width="250" height="250">
</div>
</div>
<div class="container-4">
<h2 id="change-my-color">Challenge 4:Change the color of all buttons</h2>
<div class="flex-box-pick-color">
<form action="">
<select name="backdrop" id="background" onChange="buttonColorChange(this)">
<option value="random">Random</option>
<option value="red">Red</option>
<option value="green">Green</option>
<option value="reset">Reset</option>
</select>
</form>
<button class="btn btn-primary">Wee!</button>
<button class="btn btn-danger">Yahoo!</button>
<button class="btn btn-warning">Google!</button>
<button class="btn btn-success">Facebook!</button>
</div>
</div>
</body>
</html>
CSS:
.container-1, .container-2 , .container-3 ,.container-4{
border: 1px solid blue;
width:75%;
margin: 0 auto;
text-align: center;
}
.flex-box-container-1, .flex-box-container-2,.flex-box-rps,.flex-box-pick-color{
display:flex;
border:1px solid purple;
padding: 10px;
flex-wrap:wrap;
flex-direction: row;
justify-content: space-around;
}
.flex-box-container-1 div{
display:flex;
padding: 10px;
border: 1 px solid black;
align-items: center;
}
.flex-box-container-2 img{
margin:10px;
box-shadow: 0px 10px 50px rgba(0,0,0,0.7);
}
.flex-box-rps img:hover{
box-shadow: 0px 10px 50px rgba(37,50,233,1);
}
Map button properties to a new array for later use, a minimal reproducable example.
// map button.btn properties to strings with id and class list
const all_buttons = [...document.querySelectorAll('button.btn')]
.map(b => `button#${b.id}, class: ${[...b.classList].join(', ')}`);
console.log(all_buttons);
// so ...
// save original classNames
const initialButtonClasses = [...document.querySelectorAll('button')]
.map(bttn => [...bttn.classList]);
// replacement classes
const green = [`btn`, `green`];
document.addEventListener(`click`, handle);
function handle(evt) {
if (evt.target.dataset.reset) {
return document.querySelectorAll('button.btn')
.forEach((btn, i) => {
btn.classList.remove(...btn.classList);
btn.classList.add(...initialButtonClasses[i]);
});
}
if (evt.target.dataset.green) {
return document.querySelectorAll('button.btn')
.forEach((btn, i) => {
btn.classList.remove(...btn.classList);
btn.classList.add(...green);
});
}
}
.green {
color: green;
}
<button id="a" class="btn z">bttnA</button>
<button id="b" class="btn y">bttnB</button>
<button id="c" class="btn x">bttnC</button>
<button data-green="1">all green</button>
<button data-reset="1">reset</button>
After searching for a long time, I found that I made a mistake in index.html, script tag should be put at the end of the body.

Attempting to Build a Calculator with JS

Just finished a code to build a calculator from a YT tutorial. The calculator looks great but I can't get it to work. I don't understand I did everything in the video verbatim. Can anyone help me out? I watched the video a few times but I just can't get it to work and can't figure out why. I'm guessing it's something wrong with the appendNumber variable. But I'm not sure still a newb to JS.
class Calculator {
constructor(previousOperandTextElement, currentOperandTextElement) {
this.previousOperandTextElement = previousOperandTextElement
this.currentOperandTextElement = currentOperandTextElement
this.clear()
}
clear(){
this.currentOperand = ''
this.previousOperand = ''
this.operation = undefined
}
delete(){
this.currentOperand = this.currentOperand.toString().slice(0, -1)
}
appendNumber(number) {
if(number === '.' && this.currentOperand.includes('.')) return
this.currentOperand = this.currentOperand.toString() + number.toString()
}
chooseOperation(operation){
if (this.currentOperand === '') return
if (this.previousOperand !== '') {
this.compute()
}
this.operation = operation
this.previousOperand = this.currentOperand
this.currentOperand = ''
}
compute(){
let computation
const prev = parseFloat(this.previousOperand)
const current = parseFloat(this.currentOperand)
if (isNaN(prev) || is NaN(current)) return
switch (this.operation){
case '+':
computation = prev + current
break
case '-':
computation = prev - current
break
case '*':
computation = prev * current
break
case '&#247':
computation = prev / current
break
default:
return
}
this.currentOperand = computation
this.operation = undefined
this.previousOperand = ''
}
getDisplayNumber(number) {
const stringNumber = number.toString()
const interDigits = parseFloat(stringNumber.split('.')[0])
const decimalDigits = stringNumber.split('.')[1]
let interDisplay
if (isNaN(interDigits)) {
integerDisplay = ''
} else {
integerDisplay integerDigits.tpLocaleString('en', {
maximumFractionDigits: 0 })
if(decimalDigits != null) {
return `$(integerDisplay).$(decimalDigits)`
}else{
return itegerDisplay
}
}
updateDisplay(){
this.currentOperandTextElement.innerText =
this.getDisplayNumber(this.currentOperand)
if(this.operation !=null){
this.previousOperandTextElement.innerText =
$(this.getDisplayNumber(this.previousOperand) $(this.operation)
}else {
this.previousOperandTextElement = ''
}
}
const numberButtons = document.querySelectorAll('[data-number]')
const operationButtons = document.querySelectorAll('[data-operation]')
const equalsButton = document.querySelector('[data-equals]')
const deleteButton = document.querySelector('[data-delete]')
const allClearButton = document.querySelector('[data-all-clear]')
const previousOperandTextElement = document.querySelector('[data-previous-operand]')
const currentOperandTextElement = document.querySelector('[data-current-operand]')
const calculator = new Calculator(previousOperandTextElement, currentOperandTextElement)
numberButtons.forEach(button => {
button.addEventListener('click', () => {
calculator.appendNumber(button.innerText)
calculator.updateDisplay()
})
})
operationButtons.forEach(button => {
button.addEventListener('click', () => {
calculator.chooseOperation(button.innerText)
calculator.updateDisplay()
})
})
equalsButton.addEventListener('click, button => {
calculator.compute()
calculator.updateDisplay()
})
allClearButton.addEventListener('click, button => {
calculator.clear()
calculator.updateDisplay()
})
deleteButton.addEventListener('click, button => {
calculator.delete()
calculator.updateDisplay()
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>New JS</title>
<style>
*, *::before, *::after{
box-sizing:border-box;
font-weight:normal;
font-family: Gotham Rounded, sans-serif;
color:Blue;
}
body{
padding:0;
margin:0;
background: linear-gradient(to right,blue, green);
}
.calculator-grid{
display:grid;
justify-content:center;
align-content:center;
min-height:100vh;
grid-template-columns:repeat(4, 100px);
grid-template-rows: minmax(120px, auto) repeat(5, 100px);
}
.calculator-grid > button {
cursor:pointer;
font-size: 2rem;
border:1px solid white;
outline:none;
background-color:rgba(255, 255, 255, .75);
}
.calculator-grid > button:hover{
background-color:rgba(255, 255, 255, .9);
}
.span-two{
grid-column: span 2;
}
.output{
grid-column:1 /-1;
background-color:rgba(0,0, .75);
display:flex;
align-items:flex-end;
justify-content: space-around;
flex-direction:column;
padding:10px;
word-wrap; break-word;
word-break:break-all;
}
.output .previous-operand{
color:rgba(255, 255, 255, .75);
font-size: 1.5rem;
}
.output .current-operand{
color:white;
font-size:2.5rem;
}
</style>
<script src="calculator.js" defer> </script>
</head>
<body>
<div class="calculator-grid">
<div class="output">
<div data-previous-operand class="previous-operand"></div>
<div data-current-operand class="current-operand"></div>
</div>
<button data-all-clear class="span-two">AC</button>
<button data-delete>DEL</button>
<button data-operation>+</button>
<button data-number>1</button>
<button data-number>2</button>
<button data-number>3</button>
<button data-operation>*</button>
<button data-number>4</button>
<button data-number>5</button>
<button data-number>6</button>
<button data-operation> &#247 </button>
<button data-number>7</button>
<button data-number>8</button>
<button data-number>9</button>
<button data-operation>-</button>
<button data-number>.</button>
<button data-number>0</button>
<button data-equals class="span-two">=</button>
</div>
</body>
</html>
Errors in your code are mostly syntactic. For example, your code does not have .innerText for this.previousOperandTextElement = by default. The string - $ {this.getDisplayNumber (this.previousOperand)} $ {this.operation} was without quotes. The line integerDisplay = integerDigits.toLocaleString ('en', {maximumFractionDigits: 0}) was missing an equal sign.
class Calculator {
constructor(previousOperandTextElement, currentOperandTextElement) {
this.previousOperandTextElement = previousOperandTextElement
this.currentOperandTextElement = currentOperandTextElement
this.clear()
}
clear() {
this.currentOperand = ''
this.previousOperand = ''
this.operation = undefined
}
delete() {
this.currentOperand = this.currentOperand.toString().slice(0, -1)
}
appendNumber(number) {
if (number === '.' && this.currentOperand.includes('.')) return
this.currentOperand = this.currentOperand.toString() + number.toString()
}
chooseOperation(operation) {
if (this.currentOperand === '') return
if (this.previousOperand !== '') {
this.compute()
}
this.operation = operation
this.previousOperand = this.currentOperand
this.currentOperand = ''
}
compute() {
let computation
const prev = parseFloat(this.previousOperand)
const current = parseFloat(this.currentOperand)
if (isNaN(prev) || isNaN(current)) return
switch (this.operation) {
case '+':
computation = prev + current
break
case '-':
computation = prev - current
break
case '*':
computation = prev * current
break
case '÷':
computation = prev / current
break
default:
return
}
this.currentOperand = computation
this.operation = undefined
this.previousOperand = ''
}
getDisplayNumber(number) {
const stringNumber = number.toString()
const integerDigits = parseFloat(stringNumber.split('.')[0])
const decimalDigits = stringNumber.split('.')[1]
let integerDisplay
if (isNaN(integerDigits)) {
integerDisplay = ''
} else {
integerDisplay = integerDigits.toLocaleString('en', { maximumFractionDigits: 0 })
}
if (decimalDigits != null) {
return `${integerDisplay}.${decimalDigits}`
} else {
return integerDisplay
}
}
updateDisplay() {
this.currentOperandTextElement.innerText =
this.getDisplayNumber(this.currentOperand)
if (this.operation != null) {
this.previousOperandTextElement.innerText =
`${this.getDisplayNumber(this.previousOperand)} ${this.operation}`
} else {
this.previousOperandTextElement.innerText = ''
}
}
}
const numberButtons = document.querySelectorAll('[data-number]')
const operationButtons = document.querySelectorAll('[data-operation]')
const equalsButton = document.querySelector('[data-equals]')
const deleteButton = document.querySelector('[data-delete]')
const allClearButton = document.querySelector('[data-all-clear]')
const previousOperandTextElement = document.querySelector('[data-previous-operand]')
const currentOperandTextElement = document.querySelector('[data-current-operand]')
const calculator = new Calculator(previousOperandTextElement, currentOperandTextElement)
numberButtons.forEach(button => {
button.addEventListener('click', () => {
calculator.appendNumber(button.innerText)
calculator.updateDisplay()
})
})
operationButtons.forEach(button => {
button.addEventListener('click', () => {
calculator.chooseOperation(button.innerText)
calculator.updateDisplay()
})
})
equalsButton.addEventListener('click', button => {
calculator.compute()
calculator.updateDisplay()
})
allClearButton.addEventListener('click', button => {
calculator.clear()
calculator.updateDisplay()
})
deleteButton.addEventListener('click', button => {
calculator.delete()
calculator.updateDisplay()
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>New JS</title>
<style>
*, *::before, *::after{
box-sizing:border-box;
font-weight:normal;
font-family: Gotham Rounded, sans-serif;
color:Blue;
}
body{
padding:0;
margin:0;
background: linear-gradient(to right,blue, green);
}
.calculator-grid{
display:grid;
justify-content:center;
align-content:center;
min-height:100vh;
grid-template-columns:repeat(4, 100px);
grid-template-rows: minmax(120px, auto) repeat(5, 100px);
}
.calculator-grid > button {
cursor:pointer;
font-size: 2rem;
border:1px solid white;
outline:none;
background-color:rgba(255, 255, 255, .75);
}
.calculator-grid > button:hover{
background-color:rgba(255, 255, 255, .9);
}
.span-two{
grid-column: span 2;
}
.output{
grid-column:1 /-1;
background-color:rgba(0,0, .75);
display:flex;
align-items:flex-end;
justify-content: space-around;
flex-direction:column;
padding:10px;
word-wrap; break-word;
word-break:break-all;
}
.output .previous-operand{
color:rgba(255, 255, 255, .75);
font-size: 1.5rem;
}
.output .current-operand{
color:white;
font-size:2.5rem;
}
</style>
<script src="calculator.js" defer> </script>
</head>
<body>
<div class="calculator-grid">
<div class="output">
<div data-previous-operand class="previous-operand"></div>
<div data-current-operand class="current-operand"></div>
</div>
<button data-all-clear class="span-two">AC</button>
<button data-delete>DEL</button>
<button data-operation>+</button>
<button data-number>1</button>
<button data-number>2</button>
<button data-number>3</button>
<button data-operation>*</button>
<button data-number>4</button>
<button data-number>5</button>
<button data-number>6</button>
<button data-operation> &#247 </button>
<button data-number>7</button>
<button data-number>8</button>
<button data-number>9</button>
<button data-operation>-</button>
<button data-number>.</button>
<button data-number>0</button>
<button data-equals class="span-two">=</button>
</div>
</body>
</html>

i'm having a lit of problem with my javascript game

i copied this little javascript game from github i started editing i made some new levels and whole new graphic design for the game. basiclly i did it for fun made new keybinds for the keyboard since it's playable for keyboard only.
then i had this idea to create a button that acts like a keyboard or directly make the character move
i tried but it don't work
so here is my "controller.js" which is responsible for the character movements
with"htmlfile.html"
const Controller = function() {
this.left = new Controller.ButtonInput();
document.getElementById("clickMe").onclick = this.right = new Controller.ButtonInput();;
this.up = new Controller.ButtonInput();
this.keyDownUp = function(type, keycode) {
var down = (type == "keydown") ? true : false;
//old//
switch(keycode) {
case 37: this.left.getInput(down); break;
case 38: this.up.getInput(down); break;
case 39: this.right.getInput(down); break;
// case 81: this.left.getInput(down); break;
// case 90: this.up.getInput(down); break;
// case 68: this.right.getInput(down);
//new//
}
};
};
//new//
//1- document.getElementById("clickMe").onclick = doFunction;
//2-document.getElementById("demo").onclick =
this.keyDownUp = function(type, button) {
var down = (type == "keydown") ? true : false;
$("input[type='button']").click(function() {
switch(button) {
case '1': this.left.getInput(down); break; //notice BREAK
case '2': this.right.getInput(down); break;
case '3': this.up.getInput(down); break;
}
});
}
Controller.prototype = {
constructor : Controller
};
Controller.ButtonInput = function() {
this.active = this.down = false;
};
Controller.ButtonInput.prototype = {
constructor : Controller.ButtonInput,
getInput : function(down) {
if (this.down != down) this.active = down;
this.down = down;
}
};
<!DOCTYPE html>
<html>
<head>
<script src="jquery-2.1.1.min.js"></script>
<!-- Added this meta tag 04/07/2018 -->
<meta name = "viewport" content = "user-scalable=no,width=device-width">
<link href = "rabbit-trap.css" rel = "stylesheet" type = "text/css">
<!--input type="text" id="demo-->
<title>Rabbit Trap</title>
</head>
<body>
<br>
<br>
<br>
<br>
<br>
<!center>
<!-- Added a menu to navigate projects from the main page -->
<div id = "menu">
<p>menu</p>
<div id = "menu-list">
<br>
part1
part2
part3
part4
part5
part6
part7
</div>
</div>
<canvas></canvas>
<!-- Since Rabbit Trap is a multi-part series and I didn't feel like writing
html and css for every single part, I decided to dynamically add the appropriate
js file containing the game logic for each part based on url parameters. -->
<script type = "text/javascript">
let part = String(window.location).split("?")[1];
/* Added on 03/09/2018 to allow reusing scripts from previous parts. */
let parts = {
"01":["01/controller-01.js", "01/display-01.js", "01/engine-01.js", "01/game-01.js", "01/main-01.js"],
"02":["02/controller-02.js", "02/display-02.js", "01/engine-01.js", "02/game-02.js", "02/main-02.js"],
"03":["02/controller-02.js", "03/display-03.js", "01/engine-01.js", "03/game-03.js", "03/main-03.js"],
"04":["02/controller-02.js", "04/display-04.js", "01/engine-01.js", "04/game-04.js", "03/main-03.js"],
"05":["02/controller-02.js", "05/display-05.js", "01/engine-01.js", "05/game-05.js", "05/main-05.js"],
"06":["02/controller-02.js", "05/display-05.js", "06/engine-06.js", "06/game-06.js", "06/main-06.js"],
"07":["02/controller-02.js", "05/display-05.js", "06/engine-06.js", "07/game-07.js", "07/main-07.js"],
};
switch(part) {
case "01": case "02": case "03": case "04": case "05": case "06": case "07": break;
default:
part = "05";
}
//new//
//<input type="button" value="button" id="movebutton" /> <!--removed inline JS-->
//new//
for (let index = 0; index < parts[part].length; index ++) {
let script = document.createElement("script");
script.setAttribute("type", "text/javascript");
script.setAttribute("src", parts[part][index]);
document.head.appendChild(script);
}
let menu = document.getElementById("menu");
let menu_list = document.getElementById("menu-list");
menu.addEventListener("click", function(event) {
menu_list.style.display = (menu_list.style.display == "none") ? "grid" : "none";
});
menu_list.style.display = "none";
</script>
<input id="clickMe" type="button" value="clickme" onclick="right" />
<input type="button" value="Change" id="1">
<input type="button" value="Change" id="2">
<input type="button" value="Change" id="3">
<!/center>
<!--new-->
<input type="button" value="button" id="demon" /?> <!--removed inline JS-->
<button id="demo" onclick="right">right</button>
</body>
</html>
sorry i know it's soo dirty code but i will try to clear the junk my self
all i need is help to create a button for movements "left,right,up"
thank you if you make it to the end and i appreciate your help
Here is an example on moving a square using both keyboard and mouse(button elements)
var pos = [0, 0], box = document.querySelector("#box"),
directions = {"37": "Left", "38": "Up", "39": "Right", "40": "Down"};
document.querySelector("#controls").onclick =
document.querySelector("body").onkeyup = function(e) {
var direction = e.type === "click" && e.target.nodeName === "BUTTON" ?
e.target.textContent : directions[e.keyCode];
switch(direction) {
case "Right": {
box.style.left = `${pos[0] + 50 > 300 ? 300 : pos[0] += 50}px`;
break;
}
case "Left": {
box.style.left = `${pos[0] - 50 < 0 ? 0 : pos[0] -= 50}px`;
break;
}
case "Down": {
box.style.top = `${pos[1] + 50 > 300 ? 300 : pos[1] += 50}px`;
break;
}
case "Up": {
box.style.top = `${pos[1] - 50 < 0 ? 0 : pos[1] -= 50}px`;
break;
}
}
};
#container {
width: 350px;
height: 350px;
background-color: orange;
border-radius: 10px;
position: relative;
}
#box {
width: 50px;
height: 50px;
background-color: blue;
border-radius: 10px;
position: absolute;
top: 0;
left: 0;
}
#controls {
margin-top: 10px;
width: 350px;
display: flex;
flex-wrap: wrap;
border-radius: 50%;
overflow: hidden;
box-shadow: 1px 1px 2px #333, -7px -2px 1px #ccc;
}
#controls button {
width: 50%;
height: 40px;
cursor: pointer;
font: bold 24px monospace;
color: white;
text-shadow: 0 0 1px black, -0 -0 1px black;
}
#controls .solo {
width: 100%;
}
#controls button:hover {
outline: none;
background-color: lightgreen;
}
<div id="container">
<div id="box"></div>
</div>
<div id="controls">
<button class="solo">Up</button>
<button>Left</button><button>Right</button>
<button class="solo">Down</button>
</div>

Connect two div by line with jquery function

I have two groups of quiz.
The first group is correct but the second group is not showing the line between two points.
The users click the point on the left and click the point on the right, then JavaScript creates a "canvas" line from the first element to the second element.
(I apologise for my english, it's my second language)
(function($) {
$.fn.connect = function(param) {
var _canvas;
var _ctx;
var _lines = new Array(); //This array will store all lines (option)
var _me = this;
var _parent = param || document;
var _lengthLines = $(_parent + ' .group1 .node').length;
var _selectFirst = null;
//Initialize Canvas object
_canvas = $('<canvas/>')
.attr('width', $(_me).width())
.attr('height', $(_me).height())
.css('position', 'absolute');
$(_parent).prepend(_canvas);
//$(_canvas).insertBefore(_parent);
this.drawLine = function(option) {
//It will push line to array.
_lines.push(option);
this.connect(option);
};
this.drawAllLine = function(option) {
/*Mandatory Fields------------------
left_selector = '.class',
data_attribute = 'data-right',
*/
if (option.left_selector != '' && typeof option.left_selector !== 'undefined' && $(option.left_selector).length > 0) {
$(option.left_selector).each(function(index) {
var option2 = new Object();
$.extend(option2, option);
option2.left_node = $(this).attr('id');
option2.right_node = $(this).data(option.data_attribute);
if (option2.right_node != '' && typeof option2.right_node !== 'undefined') {
_me.drawLine(option2);
}
});
}
};
//This Function is used to connect two different div with a dotted line.
this.connect = function(option) {
_ctx = _canvas[0].getContext('2d');
//
_ctx.beginPath();
try {
var _color;
var _dash;
var _left = new Object(); //This will store _left elements offset
var _right = new Object(); //This will store _right elements offset
var _error = (option.error == 'show') || false;
/*
option = {
left_node - Left Element by ID - Mandatory
right_node - Right Element ID - Mandatory
status - accepted, rejected, modified, (none) - Optional
style - (dashed), solid, dotted - Optional
horizantal_gap - (0), Horizantal Gap from original point
error - show, (hide) - To show error or not
width - (2) - Width of the line
}
*/
if (option.left_node != '' && typeof option.left_node !== 'undefined' && option.right_node != '' && typeof option.right_node !== 'undefined' && $(option.left_node).length > 0 && $(option.right_node).length > 0) {
//To decide colour of the line
switch (option.status) {
case 'accepted':
_color = '#0969a2';
break;
case 'rejected':
_color = '#e7005d';
break;
case 'modified':
_color = '#bfb230';
break;
case 'none':
_color = 'grey';
break;
default:
_color = 'grey';
break;
}
//To decide style of the line. dotted or solid
switch (option.style) {
case 'dashed':
_dash = [4, 2];
break;
case 'solid':
_dash = [0, 0];
break;
case 'dotted':
_dash = [4, 2];
break;
default:
_dash = [4, 2];
break;
}
/*
console.log($(option.left_node));
$(option.left_node)
$(option.right_node).data('connect',true);
*/
//If left_node is actually right side, following code will switch elements.
$(option.right_node).each(function(index, value) {
_left_node = $(option.left_node);
_right_node = $(value);
_left_node.attr('data-connect', true);
_right_node.attr('data-connect', true);
if (_left_node.offset().left >= _right_node.offset().left) {
_tmp = _left_node
_left_node = _right_node
_right_node = _tmp;
}
//Get Left point and Right Point
_left.x = _left_node.offset().left + _left_node.outerWidth();
_left.y = _left_node.offset().top + (_left_node.outerHeight() / 2);
_right.x = _right_node.offset().left;
_right.y = _right_node.offset().top + (_right_node.outerHeight() / 2);
//Create a group
//var g = _canvas.group({strokeWidth: 2, strokeDashArray:_dash});
//Draw Line
var _gap = option.horizantal_gap || 0;
_ctx.moveTo(_left.x, _left.y);
if (_gap != 0) {
_ctx.lineTo(_left.x + _gap, _left.y);
_ctx.lineTo(_right.x - _gap, _right.y);
}
_ctx.lineTo(_right.x, _right.y);
if (!_ctx.setLineDash) {
_ctx.setLineDash = function() {}
} else {
_ctx.setLineDash(_dash);
}
_ctx.lineWidth = option.width || 2;
_ctx.strokeStyle = _color;
_ctx.stroke();
});
//option.resize = option.resize || false;
} else {
if (_error) alert('Mandatory Fields are missing or incorrect');
}
} catch (err) {
if (_error) alert('Mandatory Fields are missing or incorrect');
}
//console.log(_canvas);
};
//It will redraw all line when screen resizes
$(window).resize(function() {
console.log(_me);
_me.redrawLines();
});
$(_parent + ' .group1 .node span').click(function() {
//console.log($(this).attr('data-connect'));
//[data-use="false"]
_this = this;
if ($(_this).attr('data-connect') != 'true' && $(_this).attr('data-use') == 'false') {
$(_parent + ' .group1 .node span').attr('data-use', 'false');
$(_this).attr('data-use', 'true');
_selectFirst = _this;
} else if ($(_this).attr('data-connect') == 'true') {
//console.log($(this).attr('data-id'));
//console.log(entry);
_lines.forEach(function(entry, index) {
if ($(_this).attr('data-id') == entry.id_left) {
$(entry.left_node).attr('data-use', 'false').attr('data-connect', 'false')
$(entry.right_node).attr('data-use', 'false').attr('data-connect', 'false')
_lines.splice(index, 1)
}
});
_me.redrawLines();
}
});
$(_parent + ' .group2 .node span[data-use="false"]').click(function() {
if ($(_parent + ' .group1 .node span[data-use="true"]').length == 1 && _selectFirst != null) {
if ($(this).attr('data-connect') != 'true') {
_me.drawLine({
id_left: $(_selectFirst).attr('data-id'),
id_right: $(this).attr('data-id'),
left_node: _selectFirst,
right_node: this,
horizantal_gap: 10,
error: 'show',
width: 1,
status: 'accepted'
});
$(_selectFirst).attr('data-use', 'false');
$(_selectFirst).attr('data-connect', 'true');
$(this).attr('data-use', 'false');
$(this).attr('data-connect', 'true');
}
}
});
this.redrawLines = function() {
_ctx.clearRect(0, 0, $(_me).width(), $(_me).height());
_lines.forEach(function(entry) {
entry.resize = true;
_me.connect(entry);
});
};
return this;
};
}(jQuery));
.clearfix {
clear: both;
}
body {
padding: 0px;
margin: 0px;
}
.nodes {
width: 500px
}
.node {
width: 100px;
background: #ddd;
color: #fff;
margin-bottom: 10px;
}
.group1 span {
background: #666;
border-radius: 50%;
width: 10px;
height: 10px;
margin-top: 5px;
}
.group2 span {
border: 1px solid #666;
border-radius: 50%;
width: 10px;
height: 10px;
margin-top: 5px;
}
.node span:hover {
background: #ff0000;
cursor: pointer;
}
.group1 {
float: left;
}
.group2 {
float: right;
}
.group2 .node span {
float: left;
position: relative;
left: -15px;
}
.group1 .node span {
float: right;
position: relative;
right: -15px;
}
.node span[data-connect=true] {
background: #ff00ff !important;
}
.node span[data-use=true] {
background: #ff0000 !important;
}
<div id="parentNodes_11">
<div class="nodes">
<div class="group1">
<div class="node">1<span class="node1" data-connect="false" data-id="0" data-use="false"></span></div>
<div class="node">2 <span class="node2" data-connect="false" data-id="1" data-use="false"></span></div>
<div class="node">3 <span class="node3" data-connect="false" data-id="2" data-use="false"></span></div>
</div>
<div class="group2">
<div class="node">A <span class="node4" data-connect="false" data-id="0" data-use="false"></span></div>
<div class="node">B <span class="node5" data-connect="false" data-id="1" data-use="false"></span></div>
<div class="node">C <span class="node6" data-connect="false" data-id="2" data-use="false"></span></div>
</div>
<div class="clearfix"></div>
</div>
</div>
<br>
<div id="parentNodes_12">
<div class="nodes">
<div class="group1">
<div class="node">1<span class="node1" data-connect="false" data-id="0" data-use="false"></span></div>
<div class="node">2 <span class="node2" data-connect="false" data-id="1" data-use="false"></span></div>
<div class="node">3 <span class="node3" data-connect="false" data-id="2" data-use="false"></span></div>
</div>
<div class="group2">
<div class="node">A <span class="node4" data-connect="false" data-id="0" data-use="false"></span></div>
<div class="node">B <span class="node5" data-connect="false" data-id="1" data-use="false"></span></div>
<div class="node">C <span class="node6" data-connect="false" data-id="2" data-use="false"></span></div>
</div>
<div class="clearfix"></div>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('#parentNodes_11 .nodes').connect('#parentNodes_11');
$('#parentNodes_12 .nodes').connect('#parentNodes_12');
});
</script>
This is due to the use of absolute coordinates for lines instead of relative ones, so your lines doesn't fit on the canvas.
You can just do the parent offset adjustment and it will work like this:
(function($) {
$.fn.connect = function(param) {
var _canvas;
var _ctx;
var _lines = new Array(); //This array will store all lines (option)
var _me = this;
var _parent = param || document;
var _lengthLines = $(_parent + ' .group1 .node').length;
var _selectFirst = null;
//Initialize Canvas object
_canvas = $('<canvas/>')
.attr('width', $(_me).width())
.attr('height', $(_me).height())
.css('position', 'absolute');
$(_parent).prepend(_canvas);
//$(_canvas).insertBefore(_parent);
this.drawLine = function(option) {
//It will push line to array.
_lines.push(option);
this.connect(option);
};
this.drawAllLine = function(option) {
/*Mandatory Fields------------------
left_selector = '.class',
data_attribute = 'data-right',
*/
if (option.left_selector != '' && typeof option.left_selector !== 'undefined' && $(option.left_selector).length > 0) {
$(option.left_selector).each(function(index) {
var option2 = new Object();
$.extend(option2, option);
option2.left_node = $(this).attr('id');
option2.right_node = $(this).data(option.data_attribute);
if (option2.right_node != '' && typeof option2.right_node !== 'undefined') {
_me.drawLine(option2);
}
});
}
};
//This Function is used to connect two different div with a dotted line.
this.connect = function(option) {
_ctx = _canvas[0].getContext('2d');
//
_ctx.beginPath();
try {
var _color;
var _dash;
var _left = new Object(); //This will store _left elements offset
var _right = new Object(); //This will store _right elements offset
var _error = (option.error == 'show') || false;
/*
option = {
left_node - Left Element by ID - Mandatory
right_node - Right Element ID - Mandatory
status - accepted, rejected, modified, (none) - Optional
style - (dashed), solid, dotted - Optional
horizantal_gap - (0), Horizantal Gap from original point
error - show, (hide) - To show error or not
width - (2) - Width of the line
}
*/
if (option.left_node != '' && typeof option.left_node !== 'undefined' && option.right_node != '' && typeof option.right_node !== 'undefined' && $(option.left_node).length > 0 && $(option.right_node).length > 0) {
//To decide colour of the line
switch (option.status) {
case 'accepted':
_color = '#0969a2';
break;
case 'rejected':
_color = '#e7005d';
break;
case 'modified':
_color = '#bfb230';
break;
case 'none':
_color = 'grey';
break;
default:
_color = 'grey';
break;
}
//To decide style of the line. dotted or solid
switch (option.style) {
case 'dashed':
_dash = [4, 2];
break;
case 'solid':
_dash = [0, 0];
break;
case 'dotted':
_dash = [4, 2];
break;
default:
_dash = [4, 2];
break;
}
/*
console.log($(option.left_node));
$(option.left_node)
$(option.right_node).data('connect',true);
*/
//If left_node is actually right side, following code will switch elements.
$(option.right_node).each(function(index, value) {
_left_node = $(option.left_node);
_right_node = $(value);
_left_node.attr('data-connect', true);
_right_node.attr('data-connect', true);
if (_left_node.offset().left >= _right_node.offset().left) {
_tmp = _left_node
_left_node = _right_node
_right_node = _tmp;
}
//Get Left point and Right Point
_left.x = _left_node.offset().left + _left_node.outerWidth();
_left.y = _left_node.offset().top + (_left_node.outerHeight() / 2) - _left_node.parents('.nodes').offset().top;
_right.x = _right_node.offset().left;
_right.y = _right_node.offset().top + (_right_node.outerHeight() / 2) - _right_node.parents('.nodes').offset().top;
//Create a group
//var g = _canvas.group({strokeWidth: 2, strokeDashArray:_dash});
//Draw Line
var _gap = option.horizantal_gap || 0;
_ctx.moveTo(_left.x, _left.y);
if (_gap != 0) {
_ctx.lineTo(_left.x + _gap, _left.y);
_ctx.lineTo(_right.x - _gap, _right.y);
}
_ctx.lineTo(_right.x, _right.y);
if (!_ctx.setLineDash) {
_ctx.setLineDash = function() {}
} else {
_ctx.setLineDash(_dash);
}
_ctx.lineWidth = option.width || 2;
_ctx.strokeStyle = _color;
_ctx.stroke();
});
//option.resize = option.resize || false;
} else {
if (_error) alert('Mandatory Fields are missing or incorrect');
}
} catch (err) {
if (_error) alert('Mandatory Fields are missing or incorrect');
}
//console.log(_canvas);
};
//It will redraw all line when screen resizes
$(window).resize(function() {
console.log(_me);
_me.redrawLines();
});
$(_parent + ' .group1 .node span').click(function() {
//console.log($(this).attr('data-connect'));
//[data-use="false"]
_this = this;
if ($(_this).attr('data-connect') != 'true' && $(_this).attr('data-use') == 'false') {
$(_parent + ' .group1 .node span').attr('data-use', 'false');
$(_this).attr('data-use', 'true');
_selectFirst = _this;
} else if ($(_this).attr('data-connect') == 'true') {
//console.log($(this).attr('data-id'));
//console.log(entry);
_lines.forEach(function(entry, index) {
if ($(_this).attr('data-id') == entry.id_left) {
$(entry.left_node).attr('data-use', 'false').attr('data-connect', 'false')
$(entry.right_node).attr('data-use', 'false').attr('data-connect', 'false')
_lines.splice(index, 1)
}
});
_me.redrawLines();
}
});
$(_parent + ' .group2 .node span[data-use="false"]').click(function() {
if ($(_parent + ' .group1 .node span[data-use="true"]').length == 1 && _selectFirst != null) {
if ($(this).attr('data-connect') != 'true') {
_me.drawLine({
id_left: $(_selectFirst).attr('data-id'),
id_right: $(this).attr('data-id'),
left_node: _selectFirst,
right_node: this,
horizantal_gap: 10,
error: 'show',
width: 1,
status: 'accepted'
});
$(_selectFirst).attr('data-use', 'false');
$(_selectFirst).attr('data-connect', 'true');
$(this).attr('data-use', 'false');
$(this).attr('data-connect', 'true');
}
}
});
this.redrawLines = function() {
_ctx.clearRect(0, 0, $(_me).width(), $(_me).height());
_lines.forEach(function(entry) {
entry.resize = true;
_me.connect(entry);
});
};
return this;
};
}(jQuery));
.clearfix {
clear: both;
}
body {
padding: 0px;
margin: 0px;
}
.nodes {
width: 500px
}
.node {
width: 100px;
background: #ddd;
color: #fff;
margin-bottom: 10px;
}
.group1 span {
background: #666;
border-radius: 50%;
width: 10px;
height: 10px;
margin-top: 5px;
}
.group2 span {
border: 1px solid #666;
border-radius: 50%;
width: 10px;
height: 10px;
margin-top: 5px;
}
.node span:hover {
background: #ff0000;
cursor: pointer;
}
.group1 {
float: left;
}
.group2 {
float: right;
}
.group2 .node span {
float: left;
position: relative;
left: -15px;
}
.group1 .node span {
float: right;
position: relative;
right: -15px;
}
.node span[data-connect=true] {
background: #ff00ff !important;
}
.node span[data-use=true] {
background: #ff0000 !important;
}
<div id="parentNodes_11">
<div class="nodes">
<div class="group1">
<div class="node">1<span class="node1" data-connect="false" data-id="0" data-use="false"></span></div>
<div class="node">2 <span class="node2" data-connect="false" data-id="1" data-use="false"></span></div>
<div class="node">3 <span class="node3" data-connect="false" data-id="2" data-use="false"></span></div>
</div>
<div class="group2">
<div class="node">A <span class="node4" data-connect="false" data-id="0" data-use="false"></span></div>
<div class="node">B <span class="node5" data-connect="false" data-id="1" data-use="false"></span></div>
<div class="node">C <span class="node6" data-connect="false" data-id="2" data-use="false"></span></div>
</div>
<div class="clearfix"></div>
</div>
</div>
<br>
<div id="parentNodes_12">
<div class="nodes">
<div class="group1">
<div class="node">1<span class="node1" data-connect="false" data-id="0" data-use="false"></span></div>
<div class="node">2 <span class="node2" data-connect="false" data-id="1" data-use="false"></span></div>
<div class="node">3 <span class="node3" data-connect="false" data-id="2" data-use="false"></span></div>
</div>
<div class="group2">
<div class="node">A <span class="node4" data-connect="false" data-id="0" data-use="false"></span></div>
<div class="node">B <span class="node5" data-connect="false" data-id="1" data-use="false"></span></div>
<div class="node">C <span class="node6" data-connect="false" data-id="2" data-use="false"></span></div>
</div>
<div class="clearfix"></div>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('#parentNodes_11 .nodes').connect('#parentNodes_11');
$('#parentNodes_12 .nodes').connect('#parentNodes_12');
});
</script>

Categories