How do I convert this to an OOP structure? - function

Currently, this codepen I forked displays one tv monitor on the webpage as shown below where the channel button allows the user to toggle different gif's. This gif data is stored as an array in the js file. I want to create multiple tv sets, so I am thinking it may be better to create a TV class and instantiate the TV object n-times through a loop. I am new to OOP in a web dev context, so I haven't yet figured out how to rearchitect the code to accomplish this. Since id's only allow for one HTML element, duplicating the chunk of code below would visually create another tv but without any dynamic features. What then becomes of the tv-body display elements? Would they be enveloped with a show() fx nested with the script's TV class? Thank you so much in advance!
[Cropped Output Displayed Here][1]
HTML
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>CodePen - Vintage Analog TV</title>
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"><link rel="stylesheet" href="./style.css">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="https://code.jquery.com/jquery-3.5.0.js"></script>
</head>
<body>
<!-- partial:indexe.partial.html -->
<main>
<div class="tv-set">
<div class="tv-body">
<div class="screen-container">
<canvas class="static" width="380" height="280"></canvas>
<img class="displayed" src="" alt="Nothing" width="380" height="280">
<div class="screen">
<div class="screen-frame"></div>
<div class="screen-inset"></div>
</div>
</div>
<div class="logo-badge">
<div class="logo-text">Bush</div>
</div>
<div class="controls">
<div class="panel">
<div class="screw"></div>
<div class="dial">
<button class="channel dial-label pristine">Channel</button>
</div>
</div>
<div class="vents">
<div class="vent"></div>
<div class="vent"></div>
<div class="vent"></div>
<div class="vent"></div>
<div class="vent"></div>
<div class="vent"></div>
</div>
<div class="panel">
<div class="screw"></div>
<div class="dial">
<button class="dial-label" disabled>Volume</button>
</div>
</div>
</div>
</div>
<div class="legs">
<div class="leg"></div>
<div class="leg"></div>
</div>
</div>
</main>
<!-- partial -->
<script src="./script.js"></script>
</body>
</html>
JS
document.addEventListener("DOMContentLoaded", tv);
// Helper Functions
//returns tagname
jQuery.fn.tagName = function () {
return this.prop("tagName").toLowerCase;
};
// returns nth parent from target element
$.fn.nthParent = function (n) {
var p = this;
for (var i = 0; i < n; i++)
p = p.parent();
return p;
}
phases = [{
channels: ["red", "blue"]
},
{
channels: ["green", "yellow"]
},
{
channels: ["red", "green"]
},
{
channels: ["blue", "green"]
}
]
const container = document.getElementsByTagName("main")[0];
const template = document.getElementsByClassName("tv-set")
for (let i = 0; i < phases.length; i++) {
const clone = template[i].cloneNode(true);
clone.setAttribute("id", "tv-" + (i + 1))
console.log("clone id: ", clone.getAttribute("id"))
clone.setAttribute("data-channel", 0)
clone.setAttribute("name", "tv-" + i)
// clone.style.backgroundColor = phases[i].channels[0]
container.appendChild(clone)
}
function tv() {
let cnvs = document.querySelectorAll(".static");
//Gather all static elements
// let scrns = $(".static").getContext
// console.log("Screen 01: ", scrns)
// var cnv = document.getElementById("static"),
// var cnv = document.querySelector(".static"), //works in place of line above
// Need to establish a boolean array for the isStatic
let c = []
let isStatic_arr = []
// Need to establish a boolean array for the isStatic
cnvs.forEach((cnv) => {
isStatic_arr.push(false)
var c = cnv.getContext("2d"),
cw = cnv.offsetWidth,
ch = cnv.offsetHeight,
staticScrn = c.createImageData(cw, ch),
staticFPS = 30,
// isStatic_arr.push(false),
// isStatic = false,
staticTO,
gifData = [{
// file: "https://i.ibb.co/chSK1Zt/willie.gif",
file: "./media/back-to-school-chacha.gif",
desc: "Stephen Chow Fight Back to School"
// <video controls autoplay>
// <source src="fbts_chacha_sound.mp4" type="video/mp4">
// <source src="movie.ogg" type="video/ogg">
// Your browser does not support the video tag.
// </video>
},
{
file: "https://i.ibb.co/chSK1Zt/willie.gif",
desc: "Steamboat Willie (Mickey Mouse) steering a ship"
},
{
file: "https://i.ibb.co/0FqQVrj/skeletons.gif",
desc: "Spooky scary skeletons sending shivers down your spine"
},
{
file: "https://i.ibb.co/Hpnwgq2/kingkong.gif",
desc: "King Kong waving on Empire State Building",
},
{
file: "https://i.ibb.co/fp0PSjv/tracks.gif",
desc: "Looking at train tracks from behind a train",
},
{
file: "https://i.ibb.co/5FM7BtH/nuke.gif",
desc: "Nuclear explosion at sea",
}
],
gifs = [],
channel = 0;
for (g in gifData) {
gifs.push(new Image());
gifs[g].src = gifData[g].file;
gifs[g].alt = gifData[g].desc;
}
/* Static */
var runStatic = function () {
isStatic = true;
c.clearRect(0, 0, cw, ch);
for (var i = 0; i < staticScrn.data.length; i += 4) {
let shade = 127 + Math.round(Math.random() * 128);
staticScrn.data[0 + i] = shade;
staticScrn.data[1 + i] = shade;
staticScrn.data[2 + i] = shade;
staticScrn.data[3 + i] = 255;
}
c.putImageData(staticScrn, 0, 0);
staticTO = setTimeout(runStatic, 1e3 / staticFPS);
};
runStatic();
/* Channels */
var changeChannel = function (button, idx) {
console.log("Tv-set: ", idx)
console.log("Tv-set- " + idx + "button: " + button)
// var displayed = document.getElementById("displayed");
var displayed = document.querySelectorAll(".displayed")[idx];
var display_parent = $(".displayed")[1]
console.log("Display: ", displayed)
console.log("Display's parent: ", display_parent)
++channel;
if (channel > gifData.length)
channel = 1;
// this.classList.remove("pristine");
button.classList.remove("pristine");
// this.style.transform = `rotate(${channel * 360/(gifData.length + 1)}deg)`;
button.style.transform = `rotate(${channel * 360/(gifData.length + 1)}deg)`;
theCanvas = document.querySelectorAll(".static")[idx]
// cnv.classList.remove("hide");
theCanvas.classList.remove("hide");
displayed.classList.add("hide"); //CAUSING PROBLEMS
if (!isStatic[idx])
runStatic();
setTimeout(function () {
// cnv.classList.add("hide");
theCanvas.classList.add("hide");
displayed.classList.remove("hide");
displayed.src = gifs[channel - 1].src;
displayed.alt = gifs[channel - 1].alt;
isStatic = false;
clearTimeout(staticTO);
}, 300);
};
function iterate(item, index) {
console.log(`${item} has index ${index}`);
}
// const buttons = document.getElementsByClassName("channel dial-label pristine");
// const btns_arr = Array.from(document.querySelectorAll(".channel"))
const buttons = document.querySelectorAll(".channel")
buttons.forEach((btn, i) => {
btn.addEventListener('click', () => changeChannel(btn, i));
});
});
}
[1]: https://i.stack.imgur.com/INtzP.png
[2]: https://i.stack.imgur.com/aOxoQ.png
(11/14/20) #ggirodda, thank you so much for the example. Unfortunately, I am still a bit stuck. Why is it when I use const template = document.getElementsByClassName("tv-body").children[0], I get the error: script_001.js:154 Uncaught TypeError: Cannot read property '0' of undefined
at HTMLDocument.tv (script_001.js:154) Shouldn't the tv-body class have children based on the code snippet below?
(11/14/20) Addressed error above by removing .children[0] but unsure as to why that works and why it was undefined.
(11/19/20) Resolved! Sort of, that is. All tv clones can will run as intended, meaning the static display will remain active on all tv's whose channel button has not been pressed, and the channels can be changed independently. Here were the main changes I made on the original code:
All id's replaced with classes so that they can be accessed and wrapped the "tv-body" and "legs" in a separate div so that they can be cloned as a set.
Gathered all the "tv-set" class elements outside of the tv function() and then performed the setup functions forEach()
Converted a few of the variables e.g canvas, isStatic into arrays so that their states and displays could be toggled independently. I am sure there is more work to be done here as some of the variables may still be shared among the clones.

You can take some inspiration from the code below, the example is less complex but the idea is the same
const tvs = [
{ channels: ["red", "blue"] },
{ channels: ["green", "yellow"] }
]
function changeChannel(idx) {
const tv = tvs[idx]
const tvNode = document.getElementById("tv-" + idx)
const currentChannelIdx = parseInt(tvNode.getAttribute("data-channel"))
const nextChannelIdx = tv.channels[currentChannelIdx + 1] ? currentChannelIdx + 1 : 0;
tvNode.style.backgroundColor = tv.channels[nextChannelIdx]
tvNode.setAttribute("data-channel", nextChannelIdx)
}
const container = document.getElementById("container")
const template = document.getElementById("tv-template").children[0]
for (let i = 0; i < tvs.length; i++) {
const clone = template.cloneNode(true);
clone.setAttribute("id", "tv-" + i)
clone.setAttribute("data-channel", 0)
clone.style.backgroundColor = tvs[i].channels[0]
container.appendChild(clone)
}
const buttons = document.getElementsByClassName("channel-btn")
for (let i = 0; i < buttons.length; i++) {
buttons[i].addEventListener('click', () => changeChannel(i), false);
}
<div id="container"></div>
<div id="tv-template" style="display: none;">
<div class="tv" style="width: 70px; height: 70px; margin-bottom: 20px;">
<button class="channel-btn">next</button>
</div>
</div>

Related

Using JQuery - How to show "Final Score" of a Quiz and Loop Through Questions Using an Array

I'm working on building a quiz using Jquery, Loops, and Arrays. I started with looping through the answers (seen in matrix). Now I'd like to do the same thing for questions so that each of the three options appears with a question/prompt as well. The matrix matches the dict object I have above, so I'm not sure how to replicate for questions...
Secondly, I'm having trouble getting a final score to show once we've reached the end of the arrays in the matrix. I've tried setting it so that the final score button appears once the matrix counter has reached an index beyond number of arrays, but it seems to be causing some issues. I also am having trouble returning the actual final score on the screen.
Any advice is helpful!
<body>
<div id="Start">
<div id="welcome" class="question">
<p>
Choose the right response. Don't get fired.
</p>
</div>
<button type="button" class="startBtn" id="startBtn">Start</button>
</div>
<div id="wordZone">
</div>
<ul id="choices">
<li></li>
<li></li>
<li></li>
</ul>
Next Word
Final Score
<div id="finalScore" class="hide">
<h3 id="scoreMessage"></h3>
<p id="playerScore"></p>
</div>
</body>
</html>
// setup
let score = 0;
let matrixcounter = 0;
const dict = {
officeSpeak: ["Hi there!", "Regards", "Per my last email"],
counter: 0,
};
const matrix = [
["Hi there!", "Sup dude", "Salutations"],
["Regards", "Hasta luego", "Byebye"],
[
"Per my last email",
"oopsie!",
"some other option here, you're writing this game",
],
];
const wordZone = $("#wordZone");
const choiceButtons = $("#choices li");
$("#choices").hide();
$("#end").hide();
$("#startBtn").click(function () {
$("#choices").show();
});
function buildOptions(wordCounter) {
let turnChoices = matrix[wordCounter];
$("#next").hide();
for (let i = 0, ii = turnChoices.length; i < ii; i++) {
let choiceWord = turnChoices[i];
let choiceButton = $(choiceButtons[i]);
let btnClass = "incorrect";
choiceButton.text(choiceWord);
if (dict.officeSpeak.indexOf(choiceWord) != -1) {
btnClass = "correct";
}
choiceButton.addClass(btnClass);
}
}
buildOptions(matrixcounter);
function onClickWord(e) {
console.log($(this));
$("#choices li").addClass("active");
$(".correct").css("color", "green");
$(".incorrect").css("color", "red");
if ($(this).hasClass("correct")) {
score++;
console.log(score);
}
$("#next").show();
let turnChoices = matrix[+1];
}
$("#choices li").click(onClickWord);
$("#next").click(function () {
matrixcounter++;
buildOptions(matrixcounter);
$(".correct").css("color", "black");
$(".incorrect").css("color", "black");
});
function finalScore() {
if (matrixcounter >= buildOptions(turnChoices.length)) {
$("#end").show();
}
$("#end").click(function () {
return score;
});
// let finalScore = score;
// $("#wordZone").show(finalScore);
// if (finalScore >= 2) {
// $("#wordZone").addClass("win");
// $("#win").show();
// } else {
// $("#wordZone").addClass("lose");
// $("#lose").show();
// }
}
finalScore();
I tried setting up questions as such:
const questions = [{ question: "Did you get the email I sent 5 minutes ago? Havent heard from u.", choices: ["I'm busy", "You just sent it", "Havent had a chance to look!",], correctAnswer: "Havent had a chance to look!" }, {
however it broke the loop I had previously set up to have matrix read dict as an answer key.

html div table to export excel

On my UI where I have open source project,
https://github.com/townsean/canvas-pixel-color-counter
so what I am trying to do is :-
I want to export HTML data into excel,all input div count data, earlier I was using exporting to excel plugin but it is only exporting the HTML table data not input fields data
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="author" content="Ashley G">
<meta name="description" content="A web app that counts the number of pixels in an image per a unique color.">
<title>Pixel Color Counter</title>
<link rel="shortcut icon" href="./assets/favicon.ico" type="image/x-icon">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link href="https://fonts.googleapis.com/css?family=Press+Start+2P&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Open+Sans&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css">
<button onclick="exportTableToExcel('tblData')">Export Table Data To Excel File</button>
</head>
<body>
<header>
<h1>Pixel Color Counter</h1>
</header>
<main>
<!-- About Section -->
<section id="about">
<h2>Count Pixels by Color</h2>
<p>Pixel Color Counter is vanilla JS web application that accepts an image file (selected by the user) and displays the total number of pixels per a unique color. </p>
</section>
<!-- Upload Image Section -->
<section id="upload-container">
<h2>Upload an Image</h2>
<div>
<label for="image">Choose an image:</label>
<input type="file" id="image" name="image" accept="image/png, image/jpeg">
</div>
<canvas id="canvas"></canvas>
</section>
<!-- Pixel Color Swatches and Count -->
<section id="pixel-count-container" class="pixel-count-container invisible">
<h2>Pixel Counts by Color</h2>
<p><span id="color-count"></span> unique colors</p>
<div id="color-swatches" class="color-swatches">
</div>
</section>
</main>
<div id="wait-indicator" class="invisible">
<img src="assets/ashley_sprite.gif">
<p>Please Wait</p>
</div>
<footer>
Copyright © 2019 Ashley Grenon
</footer>
<script src="counter.js"></script>
<script src="main.js"></script>
</body>
</html>
and jquery
and counter js this project
// https://developer.mozilla.org/en-US/docs/Tools/Performance/Scenarios/Intensive_JavaScript
self.addEventListener("message", go);
/**
*
*/
function go(message) {
const imageData = message.data.imageData;
const colorCounts = countPixels(imageData);
self.postMessage({
"command": "done",
colorCounts
});
}
/**
* Counts the number of pixels per a unique color
* https://stackoverflow.com/questions/19499500/canvas-getimagedata-for-optimal-performance-to-pull-out-all-data-or-one-at-a
*/
function countPixels(data) {
const colorCounts = {};
for(let index = 0; index < data.length; index += 4) {
const rgba = `rgba(${data[index]}, ${data[index + 1]}, ${data[index + 2]}, ${(data[index + 3] / 255)})`;
if (rgba in colorCounts) {
colorCounts[rgba] += 1;
} else {
colorCounts[rgba] = 1;
}
}
return colorCounts;
}
and main.js
// To avoid Uncaught DOMException while using Web Workers
// Run python -m http.server 8000
// https://stackoverflow.com/questions/8170431/using-web-workers-for-drawing-using-native-canvas-functions
const worker = new Worker('./counter.js');
handleWorkerCompletion = (message) => {
if(message.data.command == "done") {
// draw color swatches
this.drawColorSwatch(message.data.colorCounts);
worker.removeEventListener("message", handleWorkerCompletion);
// hide wait indicator
const waitIndicator = document.getElementById("wait-indicator");
waitIndicator.classList.add("invisible");
waitIndicator.classList.remove("fadein");
// scroll to color swatch section
const pixelCountContainer = document.getElementById('pixel-count-container');
pixelCountContainer.scrollIntoView({ behavior: 'smooth'});
const colorCountLabel = document.getElementById('color-count');
colorCountLabel.innerText = Object.keys(message.data.colorCounts).length;
}
};
/**
* Event listener for when the file upload has been updated
*/
document.getElementById("image").addEventListener('change', (e) => {
this.loadImage(e.target.files[0]);
}, false);
/**
* Given a valid image file, load the image into the canvas
* Good explantation the the image data: https://css-tricks.com/manipulating-pixels-using-canvas/#article-header-id-1
*/
loadImage = (file) => {
const url = window.URL.createObjectURL(file);
const img = new Image();
img.src = url;
img.onload = () => {
this.reset();
const canvas = document.getElementById('canvas');
canvas.width = img.width;
canvas.height = img.height;
const context = canvas.getContext('2d');
context.drawImage(img, 0, 0);
const uploadContainer = document.getElementById('upload-container');
uploadContainer.appendChild(img);
const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
window.URL.revokeObjectURL(this.src);
worker.addEventListener("message", handleWorkerCompletion, false);
worker.postMessage({
"imageData": imageData.data
});
const waitIndicator = document.getElementById("wait-indicator");
waitIndicator.classList.remove("invisible");
waitIndicator.classList.add("fadein");
}
};
/**
*
*/
drawColorSwatch = (colorCount) => {
let colorSwatches = document.getElementById('color-swatches');
for(const color in colorCount) {
const container = document.createElement("section");
const swatch = document.createElement("div");
const colorCountLabel = document.createElement("span");
container.classList.add("color-swatch-container");
swatch.classList.add("color-swatch");
swatch.style.background = color;
swatch.title = color;
colorCountLabel.innerHTML = `: ${colorCount[color]}`;
container.appendChild(swatch);
container.appendChild(colorCountLabel);
colorSwatches.appendChild(container);
}
let pixelCountContainer = document.getElementById('pixel-count-container');
pixelCountContainer.classList.remove('invisible');
};
/**
* Clear DOM of past color counting
*/
reset = () => {
let pixelCountContainer = document.getElementById('pixel-count-container');
pixelCountContainer.classList.add('invisible');
let colorSwatches = document.getElementById('color-swatches');
while (colorSwatches.firstChild) {
colorSwatches.removeChild(colorSwatches.firstChild);
}
let uploadContainer = document.getElementById('upload-container');
let image = uploadContainer.getElementsByTagName('img')[0];
if (image) {
uploadContainer.removeChild(image);
}
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);
}
function exportTableToExcel(color-swatches, filename = ''){
var downloadLink;
var dataType = 'application/vnd.ms-excel';
var tableSelect = document.getElementById(color-swatches);
var tableHTML = tableSelect.outerHTML.replace(/ /g, '%20');
// Specify file name
filename = filename?filename+'.xls':'excel_data.xls';
// Create download link element
downloadLink = document.createElement("a");
document.body.appendChild(downloadLink);
if(navigator.msSaveOrOpenBlob){
var blob = new Blob(['\ufeff', tableHTML], {
type: dataType
});
navigator.msSaveOrOpenBlob( blob, filename);
}else{
// Create a link to the file
downloadLink.href = 'data:' + dataType + ', ' + tableHTML;
// Setting the file name
downloadLink.download = filename;
//triggering the function
downloadLink.click();
}
}

Variable get different result inside and outside of object

I have one question. I am doing automatic slider with option to click on dot, which picture I want to show.
But I have problem with variable, which should find SVG and then I use this variable as a value for an array.
PROBLEM IS:
If I define this variable "dot" INSIDE of my object "Slider", it finds all SVG in div element.
But if I declare this variable "dot" OUTSIDE of my object, I will find elements instead of SVG.
Problematic part is:
dot = $('.images-switch').children(), - give different results if INSIDE or OUTSIDE of object SLIDER
Can you advise me how to solve it. And give my your opinion about my solution of slider?
Code is below (var dot is defined inside Slider object = find alls SVG):
var covers = $('.fadecovers'),
cover = $('.cover'),
imagesSwitch = $('.images-switch')
i = 0,
slideCount = $('.cover').length,
slide = $('.cover'),
slideArr = jQuery.makeArray(slide),
dot = $('.images-switch').children(),
dotArr = jQuery.makeArray(dot),
n = 0;
console.log(dot);
for (n = 0; n < (slideCount); n++) {
$(dotArr[n]).attr('data', n);
};
$('.images-switch').children().first().addClass('active');
//Zaciatok objektu
var Slider = {
// nastavenie atributov objektu Slider defaultne ako null
intervalID: null,
running: false,
start: function() {
intervalID = setInterval (function () {
var dot = $('.images-switch').children(),
dotArr = jQuery.makeArray(dot);
if (i == slideCount) {i = 0};
if (cover.eq(0).is(':visible')) {i = 1};
$(slideArr).fadeOut(700);
$(slideArr[i]).fadeIn(700);
$(dotArr).removeClass('active');
$(dotArr[i]).addClass('active')
i++;
running = true;
},3500);
},
pause: function() {
//stopne vykonavanie setInterval funkcie
clearInterval(intervalID);
intervalID = null;
running = false;
},
resume: function() {
//ak nie je interval prazdny (teda ako keby neexistuje), tak spusti vykonavanie setInterval funkcie
if (!intervalID) {this.start()};
},
//zlucenie funckii na stopnutie a znovu spustenie setInterval
toggle: function() {
if (running) this.pause();
else this.resume();
},
};
Slider.start();
covers.on('click', function() {
Slider.toggle();
});
imagesSwitch.on('click', 'svg', function() {
var dot = $('.images-switch').children(),
dotArr = jQuery.makeArray(dot),
data = $(this).attr('data');
i = data;
$(slideArr).fadeOut(700);
$(slideArr[i]).fadeIn(700);
$(dotArr).removeClass('active');
$(dotArr[i]).addClass('active')
i++;
});
Here is belonging HTML code:
<header class="article-header">
<div class="container">
<h1 class="post-title">
Naše portfólio prác
</h1>
</div>
<div class="fadecovers">
<div class="cover"><img src="img/dragon-1.jpg"></div>
<div class="cover fade-out" ><img src="img/dragon-2.jpg"></div>
<div class="cover fade-out"><img src="img/dragon-3.jpg"></div>
<div class="cover fade-out" ><img src="img/dragon-4.jpg"></div>
</div>
<div class="images-switch">
<i class="fas fa-circle"></i>
<i class="fas fa-circle"></i>
<i class="fas fa-circle"></i>
<i class="fas fa-circle"></i>
</div>
</header>
I finally solved it by myself. I changed the circles made by SVG to SPAN (circle made by CSS). Now it works.

Different Images Based On A Range Of Score

I recently was following a youtube tutorial on creating a whack-a-mole type game: https://www.youtube.com/watch?v=toNFfAaWghU.
I followed the code just fine till the end and now I'm wondering if it is possible to set up a system that could detect the score of the user when the time runs out and show different pictures (1-5 star ratings) based a range of scores.
Here is the code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Whack-A-Bear!</title>
<link href='https://fonts.googleapis.com/css?family=Amatic+SC:400,700' rel='stylesheet' type='text/css'>
<link href='https://www.cssfontstack.com/Gill-Sans' rel='stylesheet' type='text/css'>
<link rel="stylesheet" href="style.css">
</head>
<body>
<audio autoplay>
<source src="Outrun - Original Arcade Music.mp3" type="audio/mpeg">
</audio>
<h1>Whack-A-Bear! <span class="score">0</span></h1>
<center><h2>But Not A Hare!!</h2></center>
<div id="timer">
<h2>Timer</h2>
<p id="TimerDisplay">00:15</p>
</div>
<center><button onClick="startGame()">Click Here To Start!</button></center>
<div class="game">
<div class="hole hole1">
<div class="mole"></div>
</div>
<div class="hole hole2">
<div class="mole"></div>
</div>
<div class="hole hole3">
<div class="mole"></div>
</div>
<div class="hole hole4">
<div class="mole"></div>
</div>
<div class="hole hole5">
<div class="mole"></div>
</div>
<div class="hole hole6">
<div class="mole"></div>
</div>
</div>
<script>
/*https://medium.freecodecamp.org/javascripts-var-let-and-const-variables-explained-with-a-story-2038e3c6b2f9 */
const holes = document.querySelectorAll('.hole');
const scoreBoard = document.querySelector('.score');
const moles = document.querySelectorAll('.mole');
/*The querySelector() method only returns the first element that matches the specified CSS selectors.
To return all the matches, use the querySelectorAll() method instead.*/
let lastHole;
let timeUp = false;
let score = 0;
//set random timing for the moles to pop up
function randomTime(min, max) {
return Math.round(Math.random() * (max - min) + min);
}
//set random holes for the moles to pop up from the list of our six holes
function randomHole(holes) {
const idx = Math.floor(Math.random() * holes.length);
const hole = holes[idx];
// if by chance, we keep getting the same one as the last one, run the function again
if (hole === lastHole) {
//shows that it was about to show you the same hole but didn't so ran the function again
console.log('Ah nah thats the same one bud');
return randomHole(holes);
}
lastHole = hole;
return hole;
}
function peep() {
var imgs = ["yes.png", "Final Hare.png"];
var i = Math.floor(Math.random() * imgs.length);
var raccoon = document.getElementById('raccoon.png');
// these random times refer to how long the mole will stay popped up
const time = randomTime(200, 1000);
const hole = randomHole(holes);
//shows the random home in a random amount of time
console.log(time, hole);
var mole = hole.querySelector(".mole");
mole.style.background = "url('" + imgs[i] + "') bottom center no-repeat";
mole.style.backgroundSize = "60%";
//triggers the CSS to get the mole to come up
hole.classList.add('up');
//makes the mole go away after it has come up => means after the time's up, remove the mole
setTimeout(() => {
hole.classList.remove('up');
//if the time is not up, then run peep () again
if (!timeUp) peep();
}, time);
}
function startGame() {
scoreBoard.textContent = 0;
timeUp = false;
score = 0;
peep();
//a Timeout function will run when time up is true at 10 seconds
setTimeout(() => timeUp = true, 15000)
var sec = 15;
var timer = setInterval(function(){
document.getElementById('TimerDisplay').innerHTML='00:'+sec;
sec--;
if (sec < 0) {
clearInterval(timer);
}
}, 1000);
}
function bonk(e) {
//function bonk will take in an event which will be us clicking each of the moles
//you can simulate a click in JS but here we don't want that to be possible
if(!e.isTrusted) return; // cheater! To prevent a fake click if the event is not trusted, not clicked with mouse
score++;
this.parentNode.classList.remove('up');
scoreBoard.textContent = score;
}
moles.forEach(mole => mole.addEventListener('click', bonk));
</script>
</body>
</html>
Use a switch statement for the image on the end screen such as
switch(true){
case score > firstStarRatingValue:
document.getElementById("END IMAGE ID").style.backgroundImage = "url(\"IMAGE1.png\")";
break;
case score > secondStarRatingValue:
document.getElementById("END IMAGE ID").style.backgroundImage = "url(\"IMAGE2.png\")";
break;
case score > thirdStarRatingValue:
document.getElementById("END IMAGE ID").style.backgroundImage = "url(\"IMAGE3.png\")";
break;
case score > fourthStarRatingValue:
document.getElementById("END IMAGE ID").style.backgroundImage = "url(\"IMAGE4.png\")";
break;
default:
//because you probably don't want an upper limit on score
document.getElementById("END IMAGE ID").style.backgroundImage = "IMAGE5.png";
}
And you would call that at the end
and because I didn't know the id for the end, i just put END IMAGE ID so that is something you'll have to change.
In the future, please cut your code down to a minimal example. It makes things easier to read for the ones trying to help.

Update directive's template on controller's variable change - angularjs

What I'm trying to do is to get a JSON object from a $http request, requested inside a controller, and build a directive that displays the multiple objects in the JSON object in a grid.
The problem is that when the object arrives, I have to process it in the directive's controller to be able to use it in the template, as such, when the JSON object changes, it is not reflected in the template. How can I make the directive know about a change in the object and force it to reload the template?
// The Directive code
amobile.directive('grid', function() {
return {
restrict: 'E',
scope: {
break: '=break',
source: '=source'
},
controller: function($scope) {
var source = $scope.source;
$scope.final_data = new Array(source.length);
if(source){
for(var j=0; j < source.length; ++j){
var total = Math.ceil(source[j]['Division'].length / $scope.break);
var data = new Array(total);
for (var i = 0; i < total; ++i) {
data[i] = source[j]['Division'].slice(i * $scope.break, (i + 1) * $scope.break);
}
$scope.final_data[j] = data;
}
}
},
templateUrl:'directives/grid.tpl.html',
replace: true
};
});
//The template
<div ng-repeat="data in final_data">
<div layout="vertical" layout-sm="horizontal" layout-padding class="" ng-repeat="row in data">
<div class="" ng-repeat="item in row">
<div flex style="width:100px">
{{item.name}}
</div>
</div>
</div>
//index.html
<div ng-controller="DivisionsCtrl as div">
<material-button ng-click="div.go()" class="material-theme-red">Button</material-button>
<div ng-if="div.data.floors">
<gridy break="3" source="div.data.floors"/>
</div>
the simplest solution would be to use watch
controller: function($scope) {
processData = function () {
var source = $scope.source;
$scope.final_data = new Array(source.length);
if(source){
for(var j=0; j < source.length; ++j){
var total = Math.ceil(source[j]['Division'].length / $scope.break);
var data = new Array(total);
for (var i = 0; i < total; ++i) {
data[i] = source[j]['Division'].slice(i * $scope.break, (i + 1) * $scope.break);
}
$scope.final_data[j] = data;
}
}
}
$scope.$watch('div.data.floors', processData, true)
},