Dynamically changing the style of an element in a loop - javascript

I'm trying to have my 3 elements marginLeft differ from each other, with each following one being bigger by 300px than the previous. Clearly, the 'px' making it a string is in the way, but I don't know how to overcome it.
function render() {
var gElOptions = document.querySelector('.options');
for (var i = 0; i < 3; i++) {
var elOptionBtn = document.createElement('button');
gElOptions.appendChild(elOptionBtn);
elOptionBtn.setAttribute('class', `option-${i}`);
var elOption = document.querySelector(`.option-${i}`);
elOption.style.marginLeft = 1000 + 'px';
// The problematic line:
if (elOption.style.marginLeft === 1000 + 'px') elOption.style.marginLeft -= 300 + 'px';
}
}
<body onload="render()">
<div class="options">
</div>
</body>

function render() {
var gElOptions = document.querySelector('.options');
for (var i = 0; i < 3; i++) {
var elOptionBtn = document.createElement('button');
elOptionBtn.innerHTML = i
gElOptions.appendChild(elOptionBtn);
elOptionBtn.setAttribute('class', `option-${i}`);
//var elOption = document.querySelector(`.option-${i}`);
elOptionBtn.style.marginLeft = i*300 + 'px';
// The problematic line:
//if (elOption.style.marginLeft === 1000 + 'px') elOption.style.marginLeft -= 300 + 'px';
}
}
render()
<div class="options"></div>

Js is only for dynamic adding buttons. (arrow right, arrow left).
Margin for each button is set in css.
const container = document.querySelector('div');
const addButton = () => {
const button = document.createElement('button');
button.textContent = "test"
container.appendChild(button);
}
const delButton = () => {
container.lastChild?.remove()
}
window.addEventListener("keydown", ({key}) => {
switch(key){
case "ArrowLeft": {
delButton();
break;
}
case "ArrowRight": {
addButton();
}
}
})
button{
margin-left: 5px;
}
button:nth-child(1){
margin-left: 10px;
}
button:nth-child(2){
margin-left: 20px;
}
button:nth-child(3){
margin-left: 30px;
}
button:nth-child(4){
margin-left: 40px;
}
button:nth-child(5){
margin-left: 50px;
}
button:nth-child(6){
margin-left: 50px;
}
<div>

Related

I need to make a high-score list for this Javascript game

I hope you can give me a hand with this. My idea is to show a list of high-scores after the game is finished for a Doodle Jump project (javascript). The high-scores are presented successfully as you will see in my code, but the presentation is poor. Hence, I want to show them in a blank page, if possible using the same html. I will leave my code for you to reproduce the issue and help me. I thought about some document command, but you tell me.
Thanks in advance.
document.addEventListener('DOMContentLoaded', () => {
const grid = document.querySelector('.grid')
const doodler = document.createElement('div')
const unMutedIcon = document.createElement('div')
let doodlerLeftSpace = 50
let startPoint = 150
let doodlerBottomSpace = startPoint
let isGameOver = false
let platformCount = 5
let platforms = []
let upTimerid
let downTimerId
let isJumping = true
let isGoingLeft = false
let isGoingRight = false
let leftTimerId
let rightTimerId
let score = 0
let context
let musicIsPlaying = false
let copyRightMessage = " DoodleJump version by Santiago Hernandez \n all rights reserved \n Copyright © "
const NO_OF_HIGH_SCORES = 10;
const HIGH_SCORES = 'highScores';
function createDoodler() {
grid.appendChild(doodler)
doodler.classList.add('doodler')
doodlerLeftSpace = platforms[0].left
doodler.style.left = doodlerLeftSpace + 'px'
doodler.style.bottom = doodlerBottomSpace + 'px'
}
function control(e) {
if (e.key === "ArrowLeft") {
moveLeft()
} else if (e.key === "ArrowRight") {
moveRight()
} else if (e.key === "ArrowUp") {
moveStraight()
}
}
class Platform {
constructor(newPlatBottom) {
this.bottom = newPlatBottom
this.left = Math.random() * 315
this.visual = document.createElement('div')
const visual = this.visual
visual.classList.add('platform')
visual.style.left = this.left + 'px'
visual.style.bottom = this.bottom + 'px'
grid.appendChild(visual)
}
}
function createPlatforms() {
for (let i = 0; i < platformCount; i++) {
let platGap = 600 / platformCount
let newPlatBottom = 100 + i * platGap
let newPlatform = new Platform(newPlatBottom)
platforms.push(newPlatform)
console.log(platforms)
}
}
function movePlatforms() {
if (doodlerBottomSpace > 200) {
platforms.forEach(platform => {
platform.bottom -= 4
let visual = platform.visual
visual.style.bottom = platform.bottom + 'px'
if (platform.bottom < 10) {
let firstPlatform = platforms[0].visual
firstPlatform.classList.remove('platform')
platforms.shift()
score++
console.log(score)
console.log(platforms)
let newPlatform = new Platform(600)
platforms.push(newPlatform)
}
})
}
}
function jump() {
clearInterval(downTimerId)
isJumping = true
upTimerId = setInterval(function() {
doodlerBottomSpace += 20
doodler.style.bottom = doodlerBottomSpace + 'px'
if (doodlerBottomSpace > startPoint + 200) {
fall()
}
}, 30)
}
function fall() {
clearInterval(upTimerId)
isJumping = false
downTimerId = setInterval(function() {
doodlerBottomSpace -= 5
doodler.style.bottom = doodlerBottomSpace + 'px'
if (doodlerBottomSpace <= 0) {
gameOver()
}
platforms.forEach(platform => {
if ((doodlerBottomSpace >= platform.bottom) &&
(doodlerBottomSpace <= platform.bottom + 15) &&
((doodlerLeftSpace + 60) >= platform.left) &&
(doodlerLeftSpace <= (platform.left + 85)) &&
!isJumping
) {
console.log('landed')
startPoint = doodlerBottomSpace
jump()
}
})
}, 30)
}
function moveLeft() {
if (isGoingRight) {
clearInterval(rightTimerId)
isGoingRight = false
}
isGoingLeft = true
leftTimerId = setInterval(function() {
if (doodlerLeftSpace >= 0) {
doodlerLeftSpace -= 5
doodler.style.left = doodlerLeftSpace + 'px'
} else moveRight()
}, 30)
}
function moveRight() {
if (isGoingLeft) {
clearInterval(leftTimerId)
isGoingLeft = false
}
isGoingRight = true
rightTimerId = setInterval(function() {
if (doodlerLeftSpace <= 340) {
doodlerLeftSpace += 5
doodler.style.left = doodlerLeftSpace + 'px'
} else moveLeft()
}, 30)
}
function moveStraight() {
isGoingRight = false
isGoingLeft = false
clearInterval(rightTimerId)
clearInterval(leftTimerId)
}
function gameOver() {
console.log('GAME OVER')
isGameOver = true
try {
context.pause()
while (grid.firstChild) {
grid.removeChild(grid.firstChild)
}
grid.innerHTML = score
clearInterval(upTimerId)
clearInterval(downTimerId)
clearInterval(leftTimerId)
clearInterval(rightTimerId)
} catch (err) {
console.log('there was an error at gameover')
while (grid.firstChild) {
grid.removeChild(grid.firstChild)
}
grid.innerHTML = score
clearInterval(upTimerId)
clearInterval(downTimerId)
clearInterval(leftTimerId)
clearInterval(rightTimerId)
}
checkHighScore()
}
function saveHighScore(score, highScores) {
const name = prompt('You got a highscore! Enter name:');
const newScore = {
score,
name
};
// 1. Add to list
highScores.push(newScore);
// 2. Sort the list
highScores.sort((a, b) => b.score - a.score);
// 3. Select new list
highScores.splice(NO_OF_HIGH_SCORES);
// 4. Save to local storage
localStorage.setItem(HIGH_SCORES, JSON.stringify(highScores));
};
function checkHighScore() {
const highScores = JSON.parse(localStorage.getItem(HIGH_SCORES)) ? ? [];
const lowestScore = highScores[NO_OF_HIGH_SCORES - 1] ? .score ? ? 0;
if (score > lowestScore) {
saveHighScore(score, highScores); // TODO
showHighScores(); // TODO
}
}
function showHighScores() {
const highScores = JSON.parse(localStorage.getItem(HIGH_SCORES)) ? ? [];
const highScoreList = document.getElementById('highScores');
highScoreList.innerHTML = highScores.map((score) =>
`<li>${score.score} - ${score.name}</li>`
);
}
function start() {
if (!isGameOver) {
createPlatforms()
createDoodler()
setInterval(movePlatforms, 30)
jump()
document.addEventListener('keyup', control)
}
}
document.addEventListener('keypressed', control)
//attach to buttom
start()
//event listener to play music
document.addEventListener('keypress', function(e) {
if (e.keyCode == 32 || e.code == "Space") {
musicIsPlaying = true
context = new Audio("Music_level1.wav");
context.play()
context.loop = true
}
}) //end of event listener
})
.grid {
width: 400px;
height: 600px;
background-color: yellow;
position: relative;
font-size: 200px;
text-align: center;
background-image: url(bluesky_level1.gif);
background-size: contain;
background-repeat: no-repeat;
background-size: 400px 600px;
margin-right: auto;
margin-left: auto;
}
.doodler {
width: 60px;
height: 85px;
position: absolute;
background-image: url(mariobros_level1.png);
background-size: contain;
background-repeat: no-repeat;
background-size: 60px 85px;
filter: brightness(1.1);
mix-blend-mode: multiply;
}
#audio {
display: none
}
.platform {
width: 85px;
height: 15px;
position: absolute;
background-image: url(platform_tramp_level1.png);
background-size: contain;
background-repeat: no-repeat;
background-size: 85px 15px;
}
.volumeIcon {
width: 30px;
height: 30px;
position: absolute;
top: 570px;
background-image: url(volumeIconMuted.png);
background-size: contain;
background-repeat: no-repeat;
background-size: 30px 30px;
}
.unmutedIcon {
width: 30px;
height: 30px;
position: absolute;
top: 570px;
background-image: url(VolumeIcon.png);
background-size: contain;
background-repeat: no-repeat;
background-size: 30px 30px;
}
#highScores {
width: 400px;
height: 300px;
font-size: 30px;
font-family: "Georgia", "Times New Roman";
text-align: center;
position: absolute;
}
<ol id="highScores"></ol>
<div class="grid">
<div class="volumeIcon"></div>
</div>
I included what I think will reproduce the situation. Hope this helps you help me.
Why not just put:
<ol id = "highScores"></ol>
within a <div> and give that a class that has display: none initally? Like this:
<div class="high-scores-container">
<ol id = "highScores"></ol>
</div>
.high-scores-container {
display: none;
height: 100%;
}
Then when you run your showHighScores() function, grab the high-scores-container div and change the display to block and then at the same time, grab the grid div and set that to display: none. That will give you the effect of displaying your high scores on a separate page but you're just doing so with JS/CSS.

Can't make a simple If Else statement work

Hello I'm making a simple counter that is counting to 3 every time i click the button. The counter works just fine, because I can see how he changes in the console. The problem is, my JS isn't affecting the CSS. When I delete the else statements and leave only one, this is the one that is working.
CSS. note: The strongAttackBtn and strongAttackBtnLoading are in the same div.
.strongAttackBtn {
height: 50px;
width: 150px;
color: black;
font-weight: 800;
}
.strongAttackBtnLoading {
position: absolute;
height: 50px;
width: 150px;
background-color: rgba(0,0,0,0.5);
}
JS
const strongAttackBtnLoading = document.querySelector('.strongAttackBtnLoading');
const strongAttackBtn = document.querySelector('.strongAttackBtn');
let strongAttackCounter = 0;
if (strongAttackCounter === 3) {
strongAttackBtnLoading.style.width = '150px';
} else if (strongAttackCounter === 2) {
strongAttackBtnLoading.style.width = '100px';
} else if (strongAttackCounter === 1) {
strongAttackBtnLoading.style.width = '50px';
} else if (strongAttackCounter === 0) {
strongAttackBtnLoading.style.width = '0px';
}
strongAttackBtn.addEventListener('click', function(){
strongAttackCounter++;
})
Try this code.
You have to assign CSS to both DIVs and put your if statement code in the addEventListener click function.
const strongAttackBtn = document.querySelector('.strongAttackBtn');
const strongAttackBtnLoading =document.querySelector('.strongAttackBtnLoading');
var strongAttackCounter = 0;
strongAttackBtn.addEventListener('click', function(){
strongAttackCounter++;
if (strongAttackCounter === 3) {
strongAttackCounter=0; // set it to zero again;
strongAttackBtnLoading.style.width = '150px';
strongAttackBtn.style.width = '150px';
} else if (strongAttackCounter === 2) {
strongAttackBtnLoading.style.width = '100px';
strongAttackBtn.style.width = '100px';
} else if (strongAttackCounter === 1) {
strongAttackBtnLoading.style.width = '50px';
strongAttackBtn.style.width = '50px';
} else if (strongAttackCounter === 0) {
strongAttackBtnLoading.style.width = '0px';
strongAttackBtn.style.width = '0px';
}
})
.strongAttackBtn {
height: 50px;
width: 150px;
color: black;
font-weight: 800;
}
.strongAttackBtnLoading {
position: absolute;
height: 50px;
width: 150px;
background-color: rgba(0,0,0,0.5);
}
<div class="strongAttackBtnLoading"><input class="strongAttackBtn" type="button" value="strongAttackBtn"></div>

How to remove an event listener and add the listener back on another element click

I am creating a simple picture matching game and I will love to make sure when the picture is clicked once, the event listener is removed, this will help me stop the user from clicking on the same image twice to get a win, and then when the user clicks on another element the listener should be added back, I tried doing this with an if statement but the listener is only removed and never added back, I decided to reload the page which somehow makes it look like a solution but I need a better solution that can help me not to reload the page but add the listener back so that the element can be clicked again after the last else if statement run.
here is the sample code below.
//Selecting query elements
const aniSpace = document.querySelector(".container");
const firstCard = document.querySelector("#fstcard");
const secondCard = document.querySelector("#sndcard");
const thirdCard = document.querySelector("#thrdcard");
const playGame = document.querySelector('#play');
const scores = document.querySelector('.scoreboard');
count = 0;
var firstIsClicked = false;
var isCat = false;
var isElephant = false;
var isDog = false;
var isButterfly = false;
var isEmpty = false;
const animatchApp = () => {
const animals = {
cat: {
image: "asset/images/cat.png",
name: "Cat"
},
dog: {
image: "asset/images/puppy.png",
name: "Dog"
},
elephant: {
image: "asset/images/elephant.png",
name: "Elephant"
},
butterfly: {
image: "asset/images/butterfly.png",
name: "butterfly"
}
}
var score = 0;
firstCard.addEventListener('click', function firstBtn() {
var type = animals.cat.name;
if (firstIsClicked === true && isCat === true) {
firstCard.innerHTML = `<img src="${animals.cat.image}">`;
firstCard.classList.add('display');
alert("You won");
score = score + 50;
console.log(score);
document.getElementById('scores').innerHTML = score;
firstIsClicked = false;
isElephant = false;
if (score >= 200){
alert("You are unstoppable, Game won.");
count = 0;
score = 0;
document.getElementById('scores').innerHTML = score;
document.getElementById('attempts').innerHTML = count;
}
firstCard.removeEventListener('click', firstBtn);
} else if (firstIsClicked === false) {
firstCard.innerHTML = `<img src="${animals.cat.image}">`;
firstCard.classList.add('display');
firstIsClicked = true;
isCat = true;
firstCard.removeEventListener('click', firstBtn);
} else if (firstIsClicked === true && isCat != true) {
alert("Not Matched");
count++;
document.getElementById('attempts').innerHTML = count;
firstCard.innerHTML = '';
secondCard.innerHTML = '';
thirdCard.innerHTML = '';
firstCard.classList.remove('display');
secondCard.classList.remove('display');
thirdCard.classList.remove('display');
firstIsClicked = false;
isCat = false;
isDog = false;
isElephant = false;
isButterfly = false;
score = 0;
document.getElementById('scores').innerHTML = score;
location.reload(true);
}
})
secondCard.addEventListener('click', function secondBtn() {
var type = animals.elephant.name;
if (firstIsClicked === true && isElephant === true) {
secondCard.innerHTML = `<img src="${animals.elephant.image}">`;
secondCard.classList.add('display');
alert("You won");
score = score + 50;
console.log(score);
document.getElementById('scores').innerHTML = score;
firstIsClicked = false;
isElephant = false;
if (score >= 200){
alert("You are unstoppable, Game won.");
count = 0;
score = 0;
document.getElementById('scores').innerHTML = score;
document.getElementById('attempts').innerHTML = count;
}
secondCard.removeEventListener('click', secondBtn);
} else if (firstIsClicked === false) {
secondCard.innerHTML = `<img src="${animals.elephant.image}">`;
secondCard.classList.add('display');
firstIsClicked = true;
isElephant = true;
secondCard.removeEventListener('click', secondBtn);
} else if (firstIsClicked === true && isElephant != true) {
alert("Not Matched");
count++;
document.getElementById('attempts').innerHTML = count;
firstCard.innerHTML = '';
secondCard.innerHTML = '';
thirdCard.innerHTML = '';
firstCard.classList.remove('display');
secondCard.classList.remove('display');
thirdCard.classList.remove('display');
firstIsClicked = false;
isCat = false;
isDog = false;
isElephant = false;
isButterfly = false;
score = 0;
document.getElementById('scores').innerHTML = score;
location.reload(true);
}
})
thirdCard.addEventListener('click', function thirdBtn() {
var type = animals.dog.name;
if (firstIsClicked === true && isDog === true) {
thirdCard.innerHTML = `<img src="${animals.dog.image}">`;
thirdCard.classList.add('display');
alert("You won");
score = score + 50;
console.log(score);
document.getElementById('scores').innerHTML = score;
firstIsClicked = false;
isDog = false;
if (score >= 200){
alert("You are unstoppable, Game won.");
count = 0;
score = 0;
document.getElementById('scores').innerHTML = score;
document.getElementById('attempts').innerHTML = count;
}
thirdCard.removeEventListener('click', thirdBtn);
} else if (firstIsClicked === false) {
thirdCard.innerHTML = `<img src="${animals.dog.image}">`;
thirdCard.classList.add('display');
firstIsClicked = true;
isDog = true;
thirdCard.removeEventListener('click', thirdBtn);
} else if (firstIsClicked === true && isDog != true) {
alert("Not Matched");
count++;
document.getElementById('attempts').innerHTML = count;
firstCard.innerHTML = '';
secondCard.innerHTML = '';
thirdCard.innerHTML = '';
firstCard.classList.remove('display');
secondCard.classList.remove('display');
thirdCard.classList.remove('display');
firstIsClicked = false;
isCat = false;
isDog = false;
isElephant = false;
isButterfly = false;
score = 0;
document.getElementById('scores').innerHTML = score;
location.reload(true);
}
})
document.getElementById('attempts').innerHTML = count;
}
animatchApp();
.h1 {
text-align: center;
background-color: azure;
background-image: url("");
}
* {
box-sizing: border-box;
}
.container {
width: 500px;
}
.card1 {
background-color: blue;
float: left;
width: 30%;
padding: 10px;
height: 150px; /* Should be removed. Only for demonstration */
border: 1px solid rgb(179, 177, 177);
transition: transform 0.8s;
transform-style: preserve-3d;
}
.card2 {
background-color: blue;
float: left;
width: 30%;
padding: 10px;
height: 150px; /* Should be removed. Only for demonstration */
border: 1px solid rgb(179, 177, 177);
transition: transform 0.8s;
transform-style: preserve-3d;}
.card3 {
background-color: blue;
float: left;
width: 30%;
padding: 10px;
height: 150px; /* Should be removed. Only for demonstration */
border: 1px solid rgb(179, 177, 177);
transition: transform 0.8s;
transform-style: preserve-3d;
}
.scoreboard {
float: left;
width: 100%;
padding: 10px;
height: 150px; /* Should be removed. Only for demonstration */
}
img {
width: 100%;
height: 100%;
background-color: white;
}
.display {
background-color: white;
transform: rotateY(180deg);
}
<div class="container">
<h1 class="h1">Animatch</h1>
<div class="first">
<div class="card1" id="fstcard"></div>
<div class="card1" id="sndcard"></div>
<div class="card1" id="thrdcard"></div>
</div>
</div>
<div class="scoreboard">
<p>
<button id="play" onclick="animatchApp()">Play</button>
<br>
Score: <span id="scores">0</span>
<br>
Failed attempts: <span id="attempts"></span>
</p>
</div>
you have to define function outside of onclick because you will need this function reference to remove or add it to eventlistener later
see a example below
function onload(){
var main = document.querySelector(".main"),
btns = main.querySelectorAll(".buttons input"),
box = main.querySelector(".box")
btns[0].addEventListener("click",function(){
box.addEventListener("click",functionForEvent)
})
btns[1].addEventListener("click",function(){
box.removeEventListener("click",functionForEvent)
})
function functionForEvent(e){
console.log("clicked")
}
}
onload()
<div class="main">
<div class="box" style="height:120px;width:120px;border:1px solid black;">Click Me</div>
<div class="buttons">
<input type="button" value="Add Event">
<input type="button" value="Remove Event">
</div>
</div>
Here is an example, that shows how to remove the click event from the item clicked and add it to the other items.
It colors the items that can be clicked green, and the item that can't be clicked red.
To keep the example short, it doesn't check, if the elements it operates on, are well defined.
function myonload() {
let elems = document.querySelectorAll('.mydiv');
for(let i = 0; i < elems.length; ++i) {
let elem = elems[i];
elem.addEventListener('click', mydiv_clicked);
}
}
function mydiv_clicked(e) {
let elems = document.querySelectorAll('.mydiv');
for(let i = 0; i < elems.length; ++i) {
let elem = elems[i];
if(elem == e.target) {
elem.removeEventListener('click', mydiv_clicked);
elem.classList.add('mycolor_clicked');
elem.classList.remove('mycolor');
// Do additional logic here
} else {
elem.addEventListener('click', mydiv_clicked);
elem.classList.remove('mycolor_clicked');
elem.classList.add('mycolor');
// Do additional logic here
}
}
}
.mydiv {
height:30px;
width: 200px;
border:1px solid black;
margin-bottom:2px;
}
.mycolor {
background-color:#00ff00;
}
.mycolor_clicked {
background-color:#ff0000;
}
<body onload="myonload()">
<div class="mydiv mycolor">First area</div>
<div class="mydiv mycolor">Second area</div>
<div class="mydiv mycolor">Third area</div>
</body>
The example shown here does not need to check if an event handler already exists, as adding the same event handler twice, replaces the existing one.
You could also add a custom attribute to your elements and toggle it, instead of adding and removing event listeners as shown here and name your attribute data-something, for example data-can-be-clicked.

Javascript end game when click on image

Hey this is my first time on Stackoverflow!
I am building a small javascript html5 game where you click on objects kind of like whack-a-mole.. The goal is to kill as many "gem green" and " gem blue" as possible in 10 seconds, and when you click on the "gem red".. the game ends and plays a sound.
I got most things to work, except I can't find a way to make the game end when clicking on "gem red".. I have tried lots of functions and listeners.. but to no avail.. can anyone help me figure this out?
Here is the code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>HTML 5 Gem Game</title>
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1">
<style>
section#game {
width: 480px;
height: 800px;
max-width: 100%;
max-height: 100%;
overflow: hidden;
position: relative;
background-image: url('img/Splash.png');
position: relative;
color: #ffffff;
font-size: 30px;
font-family: "arial,sans-serif";
}
section#game .score{
display: block;
position: absolute;
top: 10px;
left: 10px;
}
section#game .time{
display: block;
position: absolute;
top: 10px;
right: 10px;
}
section#game .start{
display: block;
padding-top: 40%;
margin: 0 auto 0 auto;
text-align: center;
width: 70%;
cursor: pointer;
}
section#game .start .high-scores{
text-align: left;
}
section#game .gem{
display: block;
position: absolute;
width: 40px;
height: 44px;
cursor: pointer;
}
section#game .gem.green{
background: url('img/Gem Green.png') no-repeat top left;
}
section#game .gem.blue{
background: url('img/Gem Blue.png') no-repeat top left;
}
section#game .gem.red{
background: url('img/Gem Red.png') no-repeat top left;
}
</style>
<script>
function addEvent(element, event, delegate ) {
if (typeof (window.event) != 'undefined' && element.attachEvent)
element.attachEvent('on' + event, delegate);
else
element.addEventListener(event, delegate, false);
}
function Game(){
var game = document.querySelector("section#game");
var score = game.querySelector("section#game span.score");
var high_scores = game.querySelector("section#game ol.high-scores");
var time = game.querySelector("section#game span.time");
var start = game.querySelector("section#game span.start");
function Gem(Class, Value, MaxTTL) {
this.Class = Class;
this.Value = Value;
this.MaxTTL = MaxTTL;
};
var gems = new Array();
gems[0] = new Gem('green', 10, 1.2);
gems[1] = new Gem('blue', 20, 1);
gems[2] = new Gem('red', 50, 0.75);
function Click(event)
{
if(event.preventDefault) event.preventDefault();
if (event.stopPropagation) event.stopPropagation();
else event.cancelBubble = true;
var target = event.target || event.srcElement;
if(target.className.indexOf('gem') > -1){
var value = parseInt(target.getAttribute('data-value'));
var current = parseInt( score.innerHTML );
var audio = new Audio('music/blaster.mp3');
audio.play();
score.innerHTML = current + value;
target.parentNode.removeChild(target);
}
return false;
}
function Remove(id) {
var gem = game.querySelector("#" + id);
if(typeof(gem) != 'undefined')
gem.parentNode.removeChild(gem);
}
function Spawn() {
var index = Math.floor( ( Math.random() * 3 ) );
var gem = gems[index];
var id = Math.floor( ( Math.random() * 1000 ) + 1 );
var ttl = Math.floor( ( Math.random() * parseInt(gem.MaxTTL) * 1000 ) + 1000 ); //between 1s and MaxTTL
var x = Math.floor( ( Math.random() * ( game.offsetWidth - 40 ) ) );
var y = Math.floor( ( Math.random() * ( game.offsetHeight - 44 ) ) );
var fragment = document.createElement('span');
fragment.id = "gem-" + id;
fragment.setAttribute('class', "gem " + gem.Class);
fragment.setAttribute('data-value', gem.Value);
game.appendChild(fragment);
fragment.style.left = x + "px";
fragment.style.top = y + "px";
setTimeout( function(){
Remove(fragment.id);
}, ttl)
}
<!-- parse high score keeper -->
function HighScores() {
if(typeof(Storage)!=="undefined"){
var scores = false;
if(localStorage["high-scores"]) {
high_scores.style.display = "block";
high_scores.innerHTML = '';
scores = JSON.parse(localStorage["high-scores"]);
scores = scores.sort(function(a,b){return parseInt(b)-parseInt(a)});
for(var i = 0; i < 10; i++){
var s = scores[i];
var fragment = document.createElement('li');
fragment.innerHTML = (typeof(s) != "undefined" ? s : "" );
high_scores.appendChild(fragment);
}
}
} else {
high_scores.style.display = "none";
}
}
function UpdateScore() {
if(typeof(Storage)!=="undefined"){
var current = parseInt(score.innerHTML);
var scores = false;
if(localStorage["high-scores"]) {
scores = JSON.parse(localStorage["high-scores"]);
scores = scores.sort(function(a,b){return parseInt(b)-parseInt(a)});
for(var i = 0; i < 10; i++){
var s = parseInt(scores[i]);
var val = (!isNaN(s) ? s : 0 );
if(current > val)
{
val = current;
scores.splice(i, 0, parseInt(current));
break;
}
}
scores.length = 10;
localStorage["high-scores"] = JSON.stringify(scores);
} else {
var scores = new Array();
scores[0] = current;
localStorage["high-scores"] = JSON.stringify(scores);
}
HighScores();
}
}
function Stop(interval) {
clearInterval(interval);
}
this.Start = function() {
score.innerHTML = "0";
start.style.display = "none";
var interval = setInterval(Spawn, 750);
var count = 10;
var counter = null;
function timer()
{
count = count-1;
if (count <= 0)
{
var left = document.querySelectorAll("section#game .gem");
for (var i = 0; i < left.length; i++) {
if(left[i] && left[i].parentNode) {
left[i].parentNode.removeChild(left[i]);
}
}
Stop(interval);
Stop(counter);
time.innerHTML = "Game Over!";
start.style.display = "block";
UpdateScore();
return;
} else {
time.innerHTML = count + "s left";
}
}
counter = setInterval(timer, 1000);
setTimeout( function(){
Stop(interval);
}, count * 1000)
};
addEvent(game, 'click', Click);
addEvent(start, 'click', this.Start);
HighScores();
}
addEvent(document, 'readystatechange', function() {
if ( document.readyState !== "complete" )
return true;
var game = new Game();
});
</script>
</head>
<body>
<div id="page">
<section id="game">
<span class="score">0</span>
<span class="time">0</span>
<span class="start">START!
<ol class="high-scores"></ol>
</span>
</section>
</div>
</body>
</html>
Alessio -
You only need a few minor changes to your code to make it work. The example below should help you get started in the right direction. Good luck.
Changes:
Add an endGame() function and move the stop game logic from the timer() function into it.
Add a line to the click() function to check for red gem clicks.
if (target.className.indexOf('red') > 0) endGame("Red Gem - You win!");
Declare the count, counter, and interval variables at the top of your Game object.
The code below also has a few minor CSS changes used for debugging which you can remove.
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<title>HTML 5 Gem Game</title>
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1">
<style>
section#game {
width: 480px;
height: 800px;
max-width: 100%;
max-height: 100%;
overflow: hidden;
position: relative;
background-image: url('img/Splash.png');
border: 1px red dotted;
position: relative;
color: red;
font-size: 30px;
font-family: "arial,sans-serif";
}
section#game .score{
display: block;
position: absolute;
top: 10px;
left: 10px;
}
section#game .time{
display: block;
position: absolute;
top: 10px;
right: 10px;
}
section#game .start{
display: block;
padding-top: 40%;
margin: 0 auto 0 auto;
text-align: center;
width: 70%;
cursor: pointer;
}
section#game .start .high-scores{
text-align: left;
}
section#game .gem{
display: block;
position: absolute;
width: 40px;
height: 44px;
cursor: pointer;
}
section#game .gem.green{
background: url('img/Gem Green.png') no-repeat top left;
background-color: green;
}
section#game .gem.blue{
background: url('img/Gem Blue.png') no-repeat top left;
background-color: blue;
}
section#game .gem.red{
background: url('img/Gem Red.png') no-repeat top left;
background-color: red;
}
</style>
<script>
function addEvent(element, event, delegate ) {
if (typeof (window.event) != 'undefined' && element.attachEvent)
element.attachEvent('on' + event, delegate);
else
element.addEventListener(event, delegate, false);
}
function Game(){
var game = document.querySelector("section#game");
var score = game.querySelector("section#game span.score");
var high_scores = game.querySelector("section#game ol.high-scores");
var time = game.querySelector("section#game span.time");
var start = game.querySelector("section#game span.start");
var interval, counter, count;
function Gem(Class, Value, MaxTTL) {
this.Class = Class;
this.Value = Value;
this.MaxTTL = MaxTTL;
};
var gems = new Array();
gems[0] = new Gem('green', 10, 1.2);
gems[1] = new Gem('blue', 20, 1);
gems[2] = new Gem('red', 50, 0.75);
function Click(event)
{
if(event.preventDefault) event.preventDefault();
if (event.stopPropagation) event.stopPropagation();
else event.cancelBubble = true;
var target = event.target || event.srcElement;
if(target.className.indexOf('gem') > -1){
var value = parseInt(target.getAttribute('data-value'));
var current = parseInt( score.innerHTML );
var audio = new Audio('music/blaster.mp3');
audio.play();
score.innerHTML = current + value;
target.parentNode.removeChild(target);
if (target.className.indexOf('red') > 0) endGame("Red Gem - You win!");
}
return false;
}
function Remove(id) {
var gem = game.querySelector("#" + id);
if(typeof(gem) != 'undefined')
gem.parentNode.removeChild(gem);
}
function Spawn() {
var index = Math.floor( ( Math.random() * 3 ) );
var gem = gems[index];
var id = Math.floor( ( Math.random() * 1000 ) + 1 );
var ttl = Math.floor( ( Math.random() * parseInt(gem.MaxTTL) * 1000 ) + 1000 ); //between 1s and MaxTTL
var x = Math.floor( ( Math.random() * ( game.offsetWidth - 40 ) ) );
var y = Math.floor( ( Math.random() * ( game.offsetHeight - 44 ) ) );
var fragment = document.createElement('span');
fragment.id = "gem-" + id;
fragment.setAttribute('class', "gem " + gem.Class);
fragment.setAttribute('data-value', gem.Value);
game.appendChild(fragment);
fragment.style.left = x + "px";
fragment.style.top = y + "px";
setTimeout( function(){
Remove(fragment.id);
}, ttl)
}
<!-- parse high score keeper -->
function HighScores() {
if(typeof(Storage)!=="undefined"){
var scores = false;
if(localStorage["high-scores"]) {
high_scores.style.display = "block";
high_scores.innerHTML = '';
scores = JSON.parse(localStorage["high-scores"]);
scores = scores.sort(function(a,b){return parseInt(b)-parseInt(a)});
for(var i = 0; i < 10; i++){
var s = scores[i];
var fragment = document.createElement('li');
fragment.innerHTML = (typeof(s) != "undefined" ? s : "" );
high_scores.appendChild(fragment);
}
}
} else {
high_scores.style.display = "none";
}
}
function UpdateScore() {
if(typeof(Storage)!=="undefined"){
var current = parseInt(score.innerHTML);
var scores = false;
if(localStorage["high-scores"]) {
scores = JSON.parse(localStorage["high-scores"]);
scores = scores.sort(function(a,b){return parseInt(b)-parseInt(a)});
for(var i = 0; i < 10; i++){
var s = parseInt(scores[i]);
var val = (!isNaN(s) ? s : 0 );
if(current > val)
{
val = current;
scores.splice(i, 0, parseInt(current));
break;
}
}
scores.length = 10;
localStorage["high-scores"] = JSON.stringify(scores);
} else {
var scores = new Array();
scores[0] = current;
localStorage["high-scores"] = JSON.stringify(scores);
}
HighScores();
}
}
function Stop(interval) {
clearInterval(interval);
}
function endGame( msg ) {
count = 0;
Stop(interval);
Stop(counter);
var left = document.querySelectorAll("section#game .gem");
for (var i = 0; i < left.length; i++) {
if(left[i] && left[i].parentNode) {
left[i].parentNode.removeChild(left[i]);
}
}
time.innerHTML = msg || "Game Over!";
start.style.display = "block";
UpdateScore();
}
this.Start = function() {
score.innerHTML = "0";
start.style.display = "none";
interval = setInterval(Spawn, 750);
count = 10;
counter = null;
function timer()
{
count = count-1;
if (count <= 0)
{
endGame();
return;
} else {
time.innerHTML = count + "s left";
}
}
counter = setInterval(timer, 1000);
setTimeout( function(){
Stop(interval);
}, count * 1000)
};
addEvent(game, 'click', Click);
addEvent(start, 'click', this.Start);
HighScores();
}
addEvent(document, 'readystatechange', function() {
if ( document.readyState !== "complete" )
return true;
var game = new Game();
});
</script>
</head>
<body>
<div id="page">
<section id="game">
<span class="score">0</span>
<span class="time">0</span>
<span class="start">START!
<ol class="high-scores"></ol>
</span>
</section>
</div>
</body>
</html>
For starters, you shouldn't include a style sheet and your entire HTML file since neither is relevant and you should use a canvas element instead of this chaotic use of CSS and html elements, which would allow the size of your code to be halved. Furthermore, you should be able to fix this by just changing some global boolean variable to false when the red gem is clicked and when the boolean variable is false (this if statement belongs at the end of your game loop) you call Stop(arg)/clearInterval(arg). Given that your current code doesn't seem to have a global boolean variable indicating game state (using an enumeration would generally be a cleaner solution but a simple boolean seems to suit this case)

Why isn't it possible to change max-height with % in javascript?

I'm trying to build a responsive menu, with a hamburger icon. I want the menu list to slide in and out, no jquery - pure javascript only.
HTML :
<div id="animation">
</div>
<button id="toggle">Toggle</button>
CSS :
div {
width: 300px;
height: 300px;
background-color: blue;
}
Javascript :
var but = document.getElementById('toggle');
var div = document.getElementById('animation');
var animate = function(type, callback){
var inter = -1, start = 100, end = 0;
if(type==true){
inter = 1;
start = 0;
end = 100;
}
var si = setInterval(function(){
console.log('maxheight');
div.style.maxHeight = (start + inter) + '%';
if(start == end){
clearInterval(si);
}
}, 10);
}
var hidden = false;
but.onclick = function(){
animate(hidden, function(){
hidden = (hidden == false) ? true : false;
});
}
div.style.maxHeight = "50%";
The problem is that proportional height in an element needs a fixed height on the parent, and you didn't provided any parent with a fixed height because for the maxHeight property too the % Defines the maximum height in % of the parent element.
You have to put your div in a parent container with a fixed height, this is your working code:
var but = document.getElementById('toggle');
var div = document.getElementById('animation');
var animate = function(type, callback) {
var inter = -1,
start = 100,
end = 0;
if (type) {
inter = 1;
start = 0;
end = 100;
}
var si = setInterval(function() {
console.log('maxheight');
div.style.maxHeight = (start + inter) + '%';
if (start == end) {
clearInterval(si);
}
}, 10);
}
var hidden = false;
but.onclick = function() {
animate(hidden, function() {
hidden = !hidden ;
});
}
div.style.maxHeight = "50%";
#animation {
width: 300px;
height: 300px;
background-color: blue;
}
#parent {
width: 500px;
height: 500px;
}
<div id="parent">
<div id="animation">
</div>
<button id="toggle">Toggle</button>
</div>
Note:
As stated in comments there are some statements in your JavaScript code that need to be adjusted:
if(type==true) can be written as if(type).
hidden = (hidden == false) ? true : false; can be shortened to hidden = !hidden
There seems to be a few errors with your code. I have fixed the js and added comments to what I have changed
var but = document.getElementById('toggle');
var div = document.getElementById('animation');
var animate = function (type, callback) {
var start = 100,
end = 0;
if (type) {
start = 0;
end = 100;
}
var si = setInterval(function () {
if (type) { // check whether to open or close animation
start++;
} else {
start--
}
div.style.maxHeight = start + '%';
if (start == end) {
clearInterval(si);
}
}, 10);
callback.call(this); // do the callback function
}
var hidden = false;
but.onclick = function () {
animate(hidden, function () {
hidden = !hidden; // set hidden to opposite
});
}
/*make sure parent container has a height set or max height won't work*/
html, body {
height:100%;
margin:0;
padding:0;
}
div {
width: 300px;
height: 300px;
background-color: blue;
}
<div id="animation"></div>
<button id="toggle">Toggle</button>
Example Fiddle

Categories