<styleSCOPED> ruin my css in my Nuxt js app - javascript

My problem is quite simple and complicated at the same time, I forked this simple HTML, CSS, JS repo : Snake game.
and then I transformed it to a Nuxt Js app : My repo .
when I use the Scoped attribute in my style tag , the Js code works fine, but with no pissibility to see the snake :
When I remove the Scoped attribute, The snake goes crazy and ouf of borders, and it ruins the style either :
my code :
window.onload = function() {
// GAME_PIXEL_COUNT is the pixels on horizontal or vertical axis of the game board (SQUARE).
const GAME_PIXEL_COUNT = 40;
const SQUARE_OF_GAME_PIXEL_COUNT = Math.pow(GAME_PIXEL_COUNT, 2);
let totalFoodAte = 0;
let totalDistanceTravelled = 0;
/// THE GAME BOARD:
const gameContainer = document.getElementById("gameContainer");
const createGameBoardPixels = () => {
// Populate the [#gameContainer] div with small div's representing game pixels
for (let i = 1; i <= SQUARE_OF_GAME_PIXEL_COUNT; ++i) {
gameContainer.innerHTML = `${gameContainer.innerHTML} <div class="gameBoardPixel" id="pixel${i}"></div>`;
}
};
// This variable always holds the updated array of game pixels created by createGameBoardPixels() :
const gameBoardPixels = document.getElementsByClassName("gameBoardPixel");
/// THE FOOD:
let currentFoodPostion = 0;
const createFood = () => {
// Remove previous food;
gameBoardPixels[currentFoodPostion].classList.remove("food");
// Create new food
currentFoodPostion = Math.random();
currentFoodPostion = Math.floor(
currentFoodPostion * SQUARE_OF_GAME_PIXEL_COUNT
);
gameBoardPixels[currentFoodPostion].classList.add("food");
};
/// THE SNAKE:
// Direction codes (Keyboard key codes for arrow keys):
const LEFT_DIR = 37;
const UP_DIR = 38;
const RIGHT_DIR = 39;
const DOWN_DIR = 40;
// Set snake direction initially to right
let snakeCurrentDirection = RIGHT_DIR;
const changeDirection = (newDirectionCode) => {
// Change the direction of the snake
if (newDirectionCode == snakeCurrentDirection) return;
if (newDirectionCode == LEFT_DIR && snakeCurrentDirection != RIGHT_DIR) {
snakeCurrentDirection = newDirectionCode;
} else if (newDirectionCode == UP_DIR && snakeCurrentDirection != DOWN_DIR) {
snakeCurrentDirection = newDirectionCode;
} else if (
newDirectionCode == RIGHT_DIR &&
snakeCurrentDirection != LEFT_DIR
) {
snakeCurrentDirection = newDirectionCode;
} else if (newDirectionCode == DOWN_DIR && snakeCurrentDirection != UP_DIR) {
snakeCurrentDirection = newDirectionCode;
}
};
// Let the starting position of the snake be at the middle of game board
let currentSnakeHeadPosition = SQUARE_OF_GAME_PIXEL_COUNT / 2;
// Initial snake length
let snakeLength = 1000;
// Move snake continously by calling this function repeatedly :
const moveSnake = () => {
switch (snakeCurrentDirection) {
case LEFT_DIR:
--currentSnakeHeadPosition;
const isSnakeHeadAtLastGameBoardPixelTowardsLeft =
currentSnakeHeadPosition % GAME_PIXEL_COUNT == GAME_PIXEL_COUNT - 1 ||
currentSnakeHeadPosition < 0;
if (isSnakeHeadAtLastGameBoardPixelTowardsLeft) {
currentSnakeHeadPosition = currentSnakeHeadPosition + GAME_PIXEL_COUNT;
}
break;
case UP_DIR:
currentSnakeHeadPosition = currentSnakeHeadPosition - GAME_PIXEL_COUNT;
const isSnakeHeadAtLastGameBoardPixelTowardsUp =
currentSnakeHeadPosition < 0;
if (isSnakeHeadAtLastGameBoardPixelTowardsUp) {
currentSnakeHeadPosition =
currentSnakeHeadPosition + SQUARE_OF_GAME_PIXEL_COUNT;
}
break;
case RIGHT_DIR:
++currentSnakeHeadPosition;
const isSnakeHeadAtLastGameBoardPixelTowardsRight =
currentSnakeHeadPosition % GAME_PIXEL_COUNT == 0;
if (isSnakeHeadAtLastGameBoardPixelTowardsRight) {
currentSnakeHeadPosition = currentSnakeHeadPosition - GAME_PIXEL_COUNT;
}
break;
case DOWN_DIR:
currentSnakeHeadPosition = currentSnakeHeadPosition + GAME_PIXEL_COUNT;
const isSnakeHeadAtLastGameBoardPixelTowardsDown =
currentSnakeHeadPosition > SQUARE_OF_GAME_PIXEL_COUNT - 1;
if (isSnakeHeadAtLastGameBoardPixelTowardsDown) {
currentSnakeHeadPosition =
currentSnakeHeadPosition - SQUARE_OF_GAME_PIXEL_COUNT;
}
break;
default:
break;
}
let nextSnakeHeadPixel = gameBoardPixels[currentSnakeHeadPosition];
// Kill snake if it bites itself:
if (nextSnakeHeadPixel.classList.contains("snakeBodyPixel")) {
// Stop moving the snake
clearInterval(moveSnakeInterval);
if (!alert(
`You have ate ${totalFoodAte} food by travelling ${totalDistanceTravelled} blocks.`
))
window.location.reload();
}
nextSnakeHeadPixel.classList.add("snakeBodyPixel");
setTimeout(() => {
nextSnakeHeadPixel.classList.remove("snakeBodyPixel");
}, snakeLength);
// Update total distance travelled
totalDistanceTravelled++;
// Update in UI:
document.getElementById("blocksTravelled").innerHTML = totalDistanceTravelled;
if (currentSnakeHeadPosition == currentFoodPostion) {
// Update total food ate
totalFoodAte++;
// Update in UI:
document.getElementById("pointsEarned").innerHTML = totalFoodAte;
// Increase Snake length:
snakeLength = snakeLength + 100;
createFood();
}
};
/// CALL THE FOLLOWING FUNCTIONS TO RUN THE GAME:
// Create game board pixels:
createGameBoardPixels();
// Create initial food:
createFood();
// Move snake:
var moveSnakeInterval = setInterval(moveSnake, 80);
// Call change direction function on keyboard key-down event:
addEventListener("keydown", (e) => changeDirection(e.keyCode));
// ON SCREEN CONTROLLERS:
const leftButton = document.getElementById("leftButton");
const rightButton = document.getElementById("rightButton");
const upButton = document.getElementById("upButton");
const downButton = document.getElementById("downButton");
leftButton.onclick = () => changeDirection(LEFT_DIR);
rightButton.onclick = () => changeDirection(RIGHT_DIR);
upButton.onclick = () => changeDirection(UP_DIR);
downButton.onclick = () => changeDirection(DOWN_DIR);
}
<style scoped>
body {
background-color: darkslategrey;
text-align: center;
}
/* GAME BOARD STYLES */
#gameContainer {
/*
width and height of .gameBoardPixel should 1/40 of the width and height of #gameContainer,
because it is used in calculation in the jscript.js file
*/
width: 40vw;
height: 40vw;
margin: 2vw auto;
background-color: #0c1021;
border: solid 10px slategrey;
border-radius: 10px;
-webkit-box-shadow: 0px 0px 20px 3px rgba(0, 0, 0, 0.6);
-moz-box-shadow: 0px 0px 20px 3px rgba(0, 0, 0, 0.6);
box-shadow: 0px 0px 20px 3px rgba(0, 0, 0, 0.6);
}
.gameBoardPixel {
/* background-color: slategrey; */
/*
width and height of .gameBoardPixel should 1/40 of the width and height of #gameContainer,
because it is used in calculation in the jscript.js file
*/
width: 1vw;
height: 1vw;
border-radius: 10px;
float: left;
}
/* GAME BOARD STYLES END*/
/* SNAKE STYLES */
.snakeBodyPixel {
background-color: #fd6401;
box-shadow: 0 0 5px #fd6401;
}
/* SNAKE STYLES END*/
/* FOOD STYLES */
.food {
background-color: #68e768;
}
/* FOOD STYLES END*/
/* SCORE STYLES */
#scoreContainer {
width: 40vw;
display: flex;
margin: auto;
justify-content: space-around;
}
.scoreBoard {
border-radius: 10px;
border: solid 5px slategrey;
color: dimgray;
background-color: #0c1021;
display: inline-block;
padding: 1vw;
width: 40%;
-webkit-box-shadow: 0px 0px 20px 3px rgba(0, 0, 0, 0.6);
-moz-box-shadow: 0px 0px 20px 3px rgba(0, 0, 0, 0.6);
box-shadow: 0px 0px 20px 3px rgba(0, 0, 0, 0.6);
}
/* SCORE STYLES END */
/* Hide #onScreenControllers on desktop */
#onScreenControllers {
display: none;
}
.developerDetails {
margin-top: 2vw;
display: flex;
flex-direction: column;
color: #0c1021;
font-family: monospace;
}
.developerDetails a {
color: #0c1021;
}
#media only screen and (max-width: 768px) {
/* MOBILE */
#gameContainer {
width: 80vw;
height: 80vw;
}
.gameBoardPixel {
width: 2vw;
height: 2vw;
}
#scoreContainer {
width: 80vw;
}
#onScreenControllers {
width: 80vw;
margin: 5vw auto;
display: flex;
justify-content: space-evenly;
align-items: center;
}
#onScreenControllers>div {
display: flex;
flex-direction: column;
}
#onScreenControllers button {
background-color: transparent;
height: 20vw;
width: 20vw;
font-size: 10vw;
border: none;
}
#onScreenControllers button:focus {
outline: none;
}
#onScreenControllers button:active {
background-color: slategray;
}
}
</style>
<template>
<body>
<div>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Snake v8</title>
<!-- #gameContainer is the main game board-->
<div id="gameContainer"></div>
<!-- #scoreContainer contains the scores -->
<div id="scoreContainer">
<div class="scoreBoard">Food: <span id="pointsEarned">0</span></div>
<div class="scoreBoard">Blocks: <span id="blocksTravelled">0</span></div>
</div>
<!-- #onScreenControllers contains the navigation buttons for mobile screens -->
<div id="onScreenControllers">
<button id="leftButton">◀️</button>
<div>
<button id="upButton">🔼</button>
<button id="downButton">🔽</button>
</div>
<button id="rightButton">▶️</button>
</div>
</div>
</body>
</template>
Any help please ? thank you

I actually found where the problem is :
in my Nuxt.js app, im using Tailwind, and it applies a default style to all my <div> tags .
the solution was to add this to my global CSS :
*
{
box-sizing: initial;
}

Related

Page does not show correct layout with small screen

The layout starts-off fine when displayed in 751px or greater but does not work fine when it starts-off in 750px or less. I thought this code below in my javascript would work but it doesn't.
// does not seem to work when page is loaded
window.addEventListener("load", () => {
window.innerWidth <= 750 ? columnLayout() : rowLayout();
});
const colorPickerEl = document.getElementById("color-picker");
const colorSchemeContainerEl = document.getElementById(
"color-scheme-container"
);
const colorModeEl = document.getElementById("color-mode");
const headerEl = document.getElementById("header");
// display default scheme
displayColorScheme(colorPickerEl.value.slice(1), "monochrome");
/*-------------
Event Listeners
---------------*/
// listen for when a new scheme is requested
document.getElementById("get-scheme-btn").addEventListener("click", () => {
displayColorScheme(colorPickerEl.value.slice(1));
});
// listen for when a randomized scheme is requested
document
.getElementById("randomize-scheme-btn")
.addEventListener("click", () => {
displayColorScheme(generateRandomColor());
});
// does not seem to work when page is loaded
window.addEventListener("load", () => {
window.innerWidth <= 750 ? columnLayout() : rowLayout();
});
window
.matchMedia("screen and (max-width: 750px)")
.addEventListener("change", (event) => {
if (event.matches) {
columnLayout();
}
});
window
.matchMedia("screen and (min-width: 751px)")
.addEventListener("change", (event) => {
if (event.matches) {
rowLayout();
}
});
function columnLayout() {
document.getElementById(
"spacer"
).style.height = `${headerEl.offsetHeight}px`;
const colorBars = document.getElementsByClassName("color-bar");
let barHeight =
(colorSchemeContainerEl.offsetHeight - headerEl.offsetHeight) / 5;
for (const bar of colorBars) {
console.log(bar);
bar.style.height = `${barHeight}px`;
}
}
function rowLayout() {
console.log("row");
const colorBars = document.getElementsByClassName("color-bar");
for (const bar of colorBars) {
bar.style.height = `${colorSchemeContainerEl.offsetHeight}px`;
}
}
// display color scheme based on user-picked color (or randomized color) and mode
function displayColorScheme(seed) {
const mode = colorModeEl.value;
// fetch the scheme using an api
fetch(`https://www.thecolorapi.com/scheme?hex=${seed}&mode=${mode}`)
// convert the data from json
.then((response) => response.json())
// manipulate the data
.then((data) => {
let html = "";
for (const color of data.colors) {
const totalRGBValue = color.rgb.r + color.rgb.g + color.rgb.b;
// 127 + 127 + 127 (the middle threshold)
const midRGBValue = 381;
const textColor =
totalRGBValue <= midRGBValue ? "white" : "black";
html += `
<div class="color-bar" style="background-color:${color.hex.value};"><p class= "text-color-bar" style="color:${textColor};">${color.hex.clean}<p></div>
`;
}
let spacer = `
<div id="spacer"></div>
`;
colorSchemeContainerEl.innerHTML = spacer + html;
});
}
// generate a random color in hex format
function generateRandomColor() {
const characters = "0123456789ABCDEF";
const maxLength = 6;
let color = "";
for (let i = 0; i < maxLength; i++) {
color += characters.charAt(
Math.floor(Math.random() * characters.length)
);
}
colorPickerEl.value = "#" + color;
return color;
}
html,
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}
form {
display: flex;
justify-content: space-evenly;
}
header {
padding: 30px 0;
background-color: transparent;
position: fixed;
top: 0;
left: 0;
width: 100%;
z-index: 99;
background-color: white;
box-shadow: 0 6px 10px -4px #222;
border-bottom-left-radius: 5px;
border-bottom-right-radius: 5px;
}
input[type="button"],
select {
padding: 0 10px;
font-size: 1.05rem;
}
#color-picker {
height: 3.5em;
width: 10%;
}
p.colorName {
border: 1.5px solid rgb(70, 70, 70);
border-radius: 5px;
padding: 10px;
}
select {
width: 30%;
text-align: center;
}
.color-bar {
display: flex;
justify-content: center;
align-items: center;
}
.text-color-bar {
margin: 0;
font-size: 1.1rem;
letter-spacing: 0.1rem;
}
#color-scheme-container {
height: 100vh;
}
#media screen and (max-width: 750px) {
#color-scheme-container {
flex-direction: column;
}
#spacer {
width: 100%;
/* height: calc(60px + 3.5em - 9px); */
}
.color-bar {
width: 100%;
/* height: 17.94%; */
}
}
#media screen and (min-width: 751px) {
#color-scheme-container {
width: 100%;
display: flex;
position: relative;
}
.color-bar {
width: 20%;
}
}
<header id="header">
<form id="color-form">
<input type="color" id="color-picker" value="#008080" />
<select name="mode" id="color-mode">
<option value="monochrome">Monochrome</option>
<option value="monochrome-dark">Monochrome Dark</option>
<option value="monochrome-light">Monochrome Light</option>
<option value="analogic">Analogic</option>
<option value="complement">Complement</option>
<option value="analogic-complement">
Analogic Complement
</option>
<option value="triad">Triad</option>
<option value="quad">Quad</option>
</select>
<input id="get-scheme-btn" type="button" value="Get Color Scheme" />
<input id="randomize-scheme-btn" type="button" value="Radomize Scheme" />
</form>
</header>
<main>
<div id="color-scheme-container"></div>
</main>
Please note that I can't get the height of my header element and assign it to my spacer div, in CSS. I have to go through my JS and set the height there. Any help is greatly appreciated.
What am I doing wrong? Why isn't the addeventlistener "load" code working?
Here's a link where you can try out the issue:
https://massuhcolorschemegenerator.netlify.app/
I found the answer! All I needed to do was put my code:
window.innerWidth <= 750 ? columnLayout() : rowLayout();
at the end of my displayColorScheme function.
It worked perfectly.

How do I stop elements from moving when the media query is triggered?

I'm a complete novice at coding.
I am styling a recent project for a course I have worked on. I have put in a media query to change the properties of the H1 and Controls class. However, when I resize the browser to trigger the media query, it is also moving the button and score out of place. Is there a reason it is doing this and how do I fix it?
Many thanks in advance!
Ray
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class='mobile'>
<div class="info">
<h1>Snake Game</h1>
<button id="start">Lets go!</button>
<h2>Score <span id="score"></span></h2>
</div>
<div class="grid"></div>
<div class="nokia"></div>
<div class="controls">
<h3>Controls</h3>
<ul><span class="direction">Up</span> - Up arrow key</ul>
<ul><span class="direction">Right</span> - Right arrow key</ul>
<ul><span class="direction">Down</span> - Down arrow key</ul>
<ul><span class="direction">Left</span> - Left arrow key</ul>
</div>
</div>
<script src="main.js"></script>
</body>
.mobile {
display: flex;
justify-content: center;
}
.nokia {
position: absolute;
top: 190px;
display: block;
width: 700px;
height: 983px;
background-image: url("https://i.imgur.com/3SeVxgS.jpg");
background-repeat: no-repeat;
background-size: 100% 100%;
}
.controls {
position: absolute;
top: 100px;
display: flex;
}
#media (max-width: 930px) {
.controls {
top: 50px;
display: block;
font-size: 70%;
}
h1 {
font-size: 20px;
}
}
.grid {
position: absolute;
top: 420px;
z-index: 9999;
display: flex;
flex-wrap: wrap;
width: 200px;
height: 200px;
border: 2px solid rgba(0, 0, 0, 0.5);
background-color: white;
}
.info {
position: absolute;
z-index: 9999;
top: 0;
text-align: center;
}
h2 {
font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
position: absolute;
top: 750px;
left: 40px;
}
button {
position: absolute;
top: 663px;
left: -5px;
height: 64px;
width: 172px;
border-style: solid;
border-bottom: 50px;
border-radius: 50%;
text-align: center;
display: inline-block;
font-size: 20px;
outline: none;
}
button:active {
transform: translateY(2px);
}
.square {
width: 20px;
height: 20px;
}
.snake {
background-color:#12c258
}
.apple {
background-color: red;
border-radius: 20%;
height: 20px;
width: 20px;
box-shadow: 0 0 0 0 rgba(0, 0, 0, 1);
transform: scale(1);
animation: pulse 2s infinite;
}
#keyframes pulse {
0% {
transform: scale(0.35);
box-shadow: 0 0 0 0 rgba(0, 0, 0, 0.7);
}
50% {
transform: scale(1);
/* box-shadow: 0 0 0 10px #12c258; */
}
100% {
transform: scale(0.35);
/* box-shadow: 0 0 0 0 rgba(0, 0, 0, 0); */
}
}
const grid = document.querySelector(".grid");
const startButton = document.getElementById("start");
const scoreDisplay = document.getElementById("score");
let squares = [];
let currentSnake = [2, 1, 0];
let direction = 1;
const width = 10;
let appleIndex = 0;
let score = 0;
let intervalTime = 1000;
let speed = 0.9;
let timerId = 0;
function createGrid() {
//create 100 of these elements with a for loop
for (let i = 0; i < width * width; i++) {
//create element
const square = document.createElement("div");
//add styling to the element
square.classList.add("square");
//put the element into our grid
grid.appendChild(square);
//push it into a new squares array
squares.push(square);
}
}
createGrid();
currentSnake.forEach(index => squares[index].classList.add("snake"));
function startGame() {
//remove the snake
currentSnake.forEach(index => squares[index].classList.remove("snake"));
//remove the apple
squares[appleIndex].classList.remove("apple");
clearInterval(timerId);
currentSnake = [2, 1, 0];
score = 0;
//re add new score to browser
scoreDisplay.textContent = score;
direction = 1;
intervalTime = 1000;
generateApple();
//readd the class of snake to our new currentSnake
currentSnake.forEach(index => squares[index].classList.add("snake"));
timerId = setInterval(move, intervalTime);
}
function move() {
if (
(currentSnake[0] + width >= width * width && direction === width) || //if snake has hit bottom
(currentSnake[0] % width === width - 1 && direction === 1) || //if snake has hit right wall
(currentSnake[0] % width === 0 && direction === -1) || //if snake has hit left wall
(currentSnake[0] - width < 0 && direction === -width) || //if snake has hit top
squares[currentSnake[0] + direction].classList.contains("snake")
)
return clearInterval(timerId);
//remove last element from our currentSnake array
const tail = currentSnake.pop();
//remove styling from last element
squares[tail].classList.remove("snake");
//add square in direction we are heading
currentSnake.unshift(currentSnake[0] + direction);
//add styling so we can see it
//deal with snake head gets apple
if (squares[currentSnake[0]].classList.contains("apple")) {
//remove the class of apple
squares[currentSnake[0]].classList.remove("apple");
//grow our snake by adding class of snake to it
squares[tail].classList.add("snake");
console.log(tail);
//grow our snake array
currentSnake.push(tail);
console.log(currentSnake);
//generate new apple
generateApple();
//add one to the score
score++;
//display our score
scoreDisplay.textContent = score;
//speed up our snake
clearInterval(timerId);
console.log(intervalTime);
intervalTime = intervalTime * speed;
console.log(intervalTime);
timerId = setInterval(move, intervalTime);
}
squares[currentSnake[0]].classList.add("snake");
}
function generateApple() {
do {
appleIndex = Math.floor(Math.random() * squares.length);
} while (squares[appleIndex].classList.contains("snake"));
squares[appleIndex].classList.add("apple");
}
generateApple();
// 39 is right arrow
// 38 is for the up arrow
// 37 is for the left arrow
// 40 is for the down arrow
function control(e) {
if (e.keyCode === 39) {
console.log("right pressed");
direction = 1;
} else if (e.keyCode === 38) {
console.log("up pressed");
direction = -width;
} else if (e.keyCode === 37) {
console.log("left pressed");
direction = -1;
} else if (e.keyCode === 40) {
console.log("down pressed");
direction = +width;
}
}
document.addEventListener("keyup", control);
startButton.addEventListener("click", startGame);
The button and the score were in that "out of place" position by default but the "Snake Game" text was pushing it to the left, you can solve this issue by putting the "Snake Game" text out of the div that has the button in it.

Strike effect in Tic tac toe game

I was working on a Tic Tac Toe game and was trying to make a strike effect for the Winner's squares.
My idea was, I could take first and last squash, get their mid position and use a canvas to create a line but its not working properly.
Following is a sample code with Fiddle link:
function TicTacToe(container) {
let count = 0;
const getLabel = () => count++ % 2 === 0 ? 'X' : 'Y';
function createGrid() {
const handlerFn = function() {
this.innerText = getLabel();
this.removeEventListener('click', handlerFn);
}
Array.from({
length: 9
}, (_, i) => {
const div = document.createElement('div');
div.classList.add('tile')
div.addEventListener('click', handlerFn)
container.append(div);
});
}
function createStrikeLine() {
const tiles = document.querySelectorAll('.tile');
const [ startX, startY ] = getPosition(tiles[0]);
const [ endX, endY ] = getPosition(tiles[8]);
console.log(startX, startY, endX, endY)
const canvas = document.getElementById('ctx-strike');
const context = canvas.getContext('2d');
context.beginPath();
context.moveTo(startX, startY);
context.lineTo(endX, endY);
context.stroke();
context.closePath();
}
function getPosition(element) {
const left = element.offsetLeft;
const top = element.offsetTop;
const height = Math.floor(element.offsetWidth / 2);
return [ left + height, top + height ];
}
createGrid();
createStrikeLine();
}
const containerDiv = document.querySelector('.content');
TicTacToe(containerDiv)
div {
display: flex;
}
.container {
align-items: center;
justify-content: center;
height: 95vh;
width: 95vw;
}
.content {
flex-direction: row;
flex-wrap: wrap;
width: 30vmax;
}
#ctx-strike {
/* position: absolute; */
height: 30vmax;
border: 1px solid black;
}
.tile {
margin: 2px;
background: white;
border: 2px solid gray;
border-radius: 4px;
width: 8vw;
height: 8vw;
align-items: center;
justify-content: center;
font-size: 2em;
}
.strike-through {
position: absolute;
z-index: 1;
border-bottom: 4px solid red;
height: 6vh;
width: 21vmax;
}
.translate-45 {
-webkit-transform: rotate(45deg);
}
<div class="container">
<div class="content"></div>
<canvas id='ctx-strike'></canvas>
</div>
Now I understand, issue is with co-ordinates, but I tried to make the canvas full with, still it fails. So the question,
How to determine correct co-ordinates for any tile?
Is there a better way to make stike effect other than canvas?
Another issue i saw was, entire UI is responsive but not the canvas. If you resize container, tiles expand/shrink but the line remains same
Post the last update:
Another issue i saw was, entire UI is responsive but not the canvas. If you resize container, tiles expand/shrink but the line remains same
I thought of using div and css instead of canvas. Yes, canvas would have been less work, css is able to handle responsiveness a bit.
Idea:
I created 8 classes with possible patterns for strike through:
Row-wise: Players can win in 3 pattern if they choose same value in either of rows.
Column-wise: Players can win in 3 pattern if they choose same value in either of column.
Diagonals: They can choose in either diagonal way.
Now in my validation logic, all I have to do is decide if there is a win, choose win pattern and pass it to my function.
Sample Code
Note: I added dropdown so users can play and check these patterns individually.
function TicTacToe(container) {
const strikePatterns = [
'row-1', 'row-2', 'row-3',
'col-1', 'col-2', 'col-3',
'dig-1', 'dig-2'
];
let count = 0;
const getLabel = () => count++ % 2 === 0 ? 'X' : 'Y';
function createGrid() {
const handlerFn = function() {
this.innerText = getLabel();
this.removeEventListener('click', handlerFn);
}
Array.from({
length: 9
}, (_, i) => {
const div = document.createElement('div');
div.classList.add('tile')
div.addEventListener('click', handlerFn)
container.append(div);
});
}
function createStrikeLine(patternName) {
const div = document.createElement('div');
div.classList.add('strike-through');
div.classList.add(patternName)
container.append(div);
}
createGrid();
function createPatternSelect(value) {
const select = document.createElement('select');
strikePatterns.forEach(function(pattern) {
const option = document.createElement('option');
option.innerText = pattern;
option.value = pattern;
select.append(option);
})
if (value) {
select.value = value;
}
select.addEventListener('change', function(event) {
container.innerHTML = '';
createGrid();
createPatternSelect(this.value);
createStrikeLine(this.value);
})
container.append(select)
}
createPatternSelect();
}
const containerDiv = document.querySelector('.content');
TicTacToe(containerDiv)
div {
display: flex;
}
.container {
align-items: center;
justify-content: center;
height: 95vh;
width: 95vw;
}
.content {
flex-direction: row;
flex-wrap: wrap;
width: 30vmax;
align-items: center;
justify-content: center;
}
#ctx-strike {
position: absolute;
border: 1px solid black;
}
.tile {
margin: 2px;
background: white;
border: 2px solid gray;
border-radius: 4px;
width: 8vw;
height: 8vw;
align-items: center;
justify-content: center;
font-size: 2em;
}
.strike-through {
border-bottom: 2px solid red;
position: absolute;
width: 18vw;
height: 1px;
}
.row-1 {
margin-top: -10vw;
}
.row-2 {
margin-top: 0;
}
.row-3 {
margin-top: 8vw;
}
.col-1 {
margin-left: -9vw;
transform: rotate(90deg);
}
.col-2 {
margin-left: 0;
transform: rotate(90deg);
}
.col-3 {
margin-left: 9vw;
transform: rotate(90deg);
}
.dig-1 {
margin-top: -1vw;
width: 27vw;
transform: rotate(-45deg);
}
.dig-2 {
margin-top: -1vw;
width: 27vw;
transform: rotate(45deg);
}
<div class="container">
<div class="content"></div>
</div>

Javascript: how do you use multiple if else statments refering to different elements?

I am Completely new to JavaScript so this may be really obvious but I am trying to build an Andon system using traffic lights where if the number is above or below a certain number the light will change colour (i.e. > 5 = green). There are nine sets of lights in total, I have successfully made one light change based on the variable by using query select all and then change the opacity.
When i try and do this with the second light nothing happens. I have tried to make it work by naming my div elements in html and CSS differently e.g. "Zcircle", "A1circle"
Link to code pen.
Any help will be greatly appreciated!
Thanks
Code
HTML:
div class="Zcontainer">
<div class="Zcircle red" color="red">
</div>
<div class="Zcircle yellow" color="yellow"></div>
<div class="Zcircle green" color="green"></div>
</div>
<div class="A1container">
<div class="A1Circle red" color="red">
</div>
<div class="A1Circle yellow" color="yellow"></div>
<div class="A1Circle green" color="green"></div>
</div>
CSS
.Zcontainer {
background-color: #2c3e50;
border-radius: 60px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
position: relative;
left: 250px;
bottom: 75px;
padding: 15px 0;
height: 200px;
width: 70px;
}
.Zcircle {
background-color: rgba(0, 0, 0, 0.3);
border-radius: 100%;
position: relative;
height: 40px;
width: 40px;
}
.Zcircle::after {
border-right: 4px solid rgba(255, 255, 255, 0.6);
border-radius: 100%;
content: " ";
position: absolute;
top: 5px;
left: 0px;
width: 30px;
height: 30px;
}
.Zcircle.red {
background-color: #c0392b;
box-shadow: 0 0 20px 5px #c0392b;
}
.Zcircle.yellow {
background-color: #f1c40f;
box-shadow: 0 0 20px 5px #f1c40f;
}
.Zcircle.green {
background-color: #2ecc71;
box-shadow: 0 0 20px 5px #2ecc71;
}
.A1container {
background-color: #2c3e50;
border-radius: 60px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
position: relative;
left: 350px;
bottom: 275px;
padding: 15px 0;
height: 200px;
width: 70px;
}
.A1circle {
background-color: rgba(0, 0, 0, 0.3);
border-radius: 100%;
position: relative;
height: 40px;
width: 40px;
}
.A1circle::after {
border-right: 4px solid rgba(255, 255, 255, 0.6);
border-radius: 100%;
content: " ";
position: absolute;
top: 5px;
left: 0px;
width: 30px;
height: 30px;
}
.A1circle.red {
background-color: #c0392b;
box-shadow: 0 0 20px 5px #c0392b;
}
.A1circle.yellow {
background-color: #f1c40f;
box-shadow: 0 0 20px 5px #f1c40f;
}
.A1circle.green {
background-color: #2ecc71;
box-shadow: 0 0 20px 5px #2ecc71;
}
Javascript
//first traffic light - this one works
var myElements = document.querySelectorAll(".Zcircle");
for (var i = 0; i < myElements.length; i++) {
myElements[i].style.opacity = 0;
}
var $15a = 2 //value which will make the light change color
if ($15a > 4) {
var myElements = document.querySelectorAll(".Zcircle");
for (var x = 2; x < myElements.length; i++) {
myElements[x].style.opacity = 1;
}
} else if ($15a < 3) {
var myElements = document.querySelectorAll(".Zcircle");
for (var x = 0; x < myElements.length; i++) {
myElements[x].style.opacity = 1;
}
} else {
var myElements = document.querySelectorAll(".Zcircle");
for (var x = 1; x < myElements.length; i++) {
myElements[x].style.opacity = 1;
}
}
//second traffic light - this one doesnt work
var myElements = document.querySelectorAll(".A1circle");
for (var a = 0; a < myElements.length; a++) {
myElements[a].style.opacity = 0;
}
var $15b = 1; //value which will make the light change color
if ($15b > 4) {
var myElements = document.querySelectorAll(".A1circle");
for (var b = 2; x < myElements.length; b++) {
myElements[b].style.opacity = 1;
}
} else if ($15b < 3) {
var myElements = document.querySelectorAll(".A1circle");
for (var b = 0; b < myElements.length; b++) {
myElements[b].style.opacity = 1;
}
} else {
var myElements = document.querySelectorAll(".A1circle");
for (var b = 1; b < myElements.length; b++) {
myElements[b].style.opacity = 1;
}
}
Here is the final code you wanted.
let allZCircles = select(".Zcircle"),
allA1Circles = select(".A1Circle"),
items = 2;
//hides all the lights
setOpacity(allZCircles, 0);
setOpacity(allA1Circles, 0);
//as per op's requirnments
if(items >= 5) {
setOpacity(select(".Zcircle.green"), 1); // makes green light visible
setOpacity(select(".A1Circle.green"), 1); // makes green light visible
} else if (items < 3) {
setOpacity(select(".Zcircle.red"), 1); // makes red light visible
setOpacity(select(".A1Circle.red"), 1); // makes red light visible
} else {
setOpacity(select(".Zcircle.yellow"), 1); // makes yellow light visible
setOpacity(select(".A1Circle.yellow"), 1); // makes yellow light visible
}
function select(selector) {return document.querySelectorAll(selector); }
function setOpacity(selectors, opacity) {selectors.forEach((selector) => selector.style.opacity = opacity);}

Calculator display value reset after dislaying the result

I've built a simple calculator using JS for the sake of practice. However, I am unable to achieve the following:
After my calculator displays the result and when I click on the keys to enter a new value, the new values keep concatenating with the result. How do I reset the display value?
How do I restrict decimal point from being entered more than ones.
Source code:
const calculator = document.querySelector(".calculator");
const displayScreen = document.querySelector(".calculatorDisplay");
const numberKeys = document.querySelectorAll(".numKeys");
const operatorKeys = document.querySelectorAll(".operator");
const equalsButton = document.querySelector(".equals");
const allClear = document.querySelector(".allClear");
const decimalButton = document.querySelector(".decimalButton");
// variables
var firstOperand;
var secondOperand;
var operator;
for(var i=0; i<numberKeys.length; i++){
numberKeys[i].addEventListener("click", e=>{
const firstValue = e.target.textContent;
displayScreen.value+= firstValue;
});
}
for(var i=0; i<operatorKeys.length; i++){
operatorKeys[i].addEventListener("click", e=>{
firstOperand = displayScreen.value;
displayScreen.value = "";
operator = e.target.textContent;
});
}
equalsButton.addEventListener("click", function(){
secondOperand = displayScreen.value;
displayScreen.value = mathOperations();
});
allClear.addEventListener("click", function(){
displayScreen.value ="";
});
decimalButton.addEventListener("click", e=>{
displayScreen.value=displayScreen.value + "."
});
function mathOperations(){
let operandOne = parseFloat(firstOperand);
let operandTwo = parseFloat(secondOperand);
if(operator==="+"){
return (operandOne + operandTwo);
}
if(operator==="-"){
return (operandOne - operandTwo);
}
if(operator==="*"){
return (operandOne * operandTwo);
}
if(operator==="/"){
return (operandOne / operandTwo);
}
}
You need to declare currentValue as a global variable (next to operator for example). Then, when user clicks on equalsButton, you set currentValue to true. Then, in numberKeys handler, add a check if currentValue is true, clear displayScreen.
numberKeys[i].addEventListener("click", e => {
if (currentValue) {
displayScreen.value = '';
currentValue = false;
}
displayScreen.value += e.target.textContent;
});
I thought by mistake that displayScreen is a string, but it's the input, so the check should be displayScreen.value.length
if (displayScreen.value.charAt(displayScreen.value.length - 1) !== '.') {
const calculator = document.querySelector(".calculator");
const displayScreen = document.querySelector(".calculatorDisplay");
const numberKeys = document.querySelectorAll(".numKeys");
const operatorKeys = document.querySelectorAll(".operator");
const equalsButton = document.querySelector(".equals");
const allClear = document.querySelector(".allClear");
const decimalButton = document.querySelector(".decimalButton");
let firstOperand;
let secondOperand;
let operator;
let currentValue = false;
enterNumbers();
for (var i = 0; i < operatorKeys.length; i++) {
operatorKeys[i].addEventListener("click", e => {
firstOperand = displayScreen.value;
displayScreen.value = "";
operator = e.target.textContent;
});
}
decimalButton.addEventListener("click", e => {
if (displayScreen.value.charAt(displayScreen.value.length - 1) !== '.') {
displayScreen.value=displayScreen.value + ".";
}
});
equalsButton.addEventListener("click", function() {
currentValue = true;
secondOperand = displayScreen.value;
displayScreen.value = mathOperations();
});
allClear.addEventListener("click", function() {
displayScreen.value = "";
});
function mathOperations() {
let operandOne = parseFloat(firstOperand);
let operandTwo = parseFloat(secondOperand);
if (operator === "+") {
return operandOne + operandTwo;
}
if (operator === "-") {
return operandOne - operandTwo;
}
if (operator === "*") {
return operandOne * operandTwo;
}
if (operator === "/") {
return operandOne / operandTwo;
}
}
function enterNumbers() {
for (var i = 0; i < numberKeys.length; i++) {
numberKeys[i].addEventListener("click", e => {
if (currentValue) {
displayScreen.value = '';
currentValue = false;
}
displayScreen.value += e.target.textContent;
});
}
}
/* Code from freshman.tech by Ayooluwa Isaiah */
html {
font-size: 62.5%;
box-sizing: border-box;
}
h1 {
text-align: center;
}
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: inherit;
}
.calculator {
border: 1px solid black;
border-radius: 25px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 400px;
}
.calculatorDisplay {
text-align: right;
font-size: 5rem;
width: 100%;
height: 80px;
border: none;
background-color: #252525;
color: #fff;
text-align: right;
padding-right: 20px;
padding-left: 10px;
}
button {
height: 60px;
border-radius: 3px;
border: 1px solid #c4c4c4;
background-color: transparent;
font-size: 2rem;
color: #333;
background-image: linear-gradient(
to bottom,
transparent,
transparent 50%,
rgba(0, 0, 0, 0.04)
);
box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.05),
inset 0 1px 0 0 rgba(255, 255, 255, 0.45),
inset 0 -1px 0 0 rgba(255, 255, 255, 0.15),
0 1px 0 0 rgba(255, 255, 255, 0.15);
text-shadow: 0 1px rgba(255, 255, 255, 0.4);
}
button:hover {
background-color: #eaeaea;
}
.operator {
color: #337cac;
}
.allClear {
background-color: #f0595f;
border-color: #b0353a;
color: #fff;
}
.allClear:hover {
background-color: #f17377;
}
.equals {
background-color: #2e86c0;
border-color: #337cac;
color: #fff;
height: 100%;
grid-area: 2 / 4 / 6 / 5;
}
.equals:hover {
background-color: #4e9ed4;
}
.calculatorKeys {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr;
grid-gap: 20px;
padding: 20px;
}
<!DOCTYPE html>
<html>
<head>
<title>Calculator</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<h1>My Calculator</h1>
<div class="calculator">
<input type="text" name="display" class="calculatorDisplay">
<div class=calculatorKeys>
<!-- operators -->
<button class="operator">+</button>
<button class="operator">-</button>
<button class="operator">*</button>
<button class="operator">/</button>
<button class="numKeys">7</button>
<button class="numKeys">8</button>
<button class="numKeys">9</button>
<button class="numKeys">4</button>
<button class="numKeys">5</button>
<button class="numKeys">6</button>
<button class="numKeys">1</button>
<button class="numKeys">2</button>
<button class="numKeys">3</button>
<button class="numKeys">0</button>
<!-- decimal-->
<button class="decimalButton">.</button>
<!-- All clear -->
<button class="allClear">AC</button>
<!-- result -->
<button class="equals">=</button>
</div>
<script type="text/javascript" src="cal.js"></script>
</div>
</body>
</html>
https://codepen.io/moshfeu/pen/RwPQKJV?editors=1000

Categories