Javascript animation only works in one direction - javascript

The webpage I'm trying to create has a bidirectional sliding animation on it. However the animation is only partially working. To be more precise, the animation slides up, but it only slides down partway. Here's my JavaScript:
function showLayer() {
var hiddenLayer = document.getElementById("mainmenu");
var layerPosition = parseInt(hiddenLayer.style.top);
if (layerPosition > 315) {
hiddenLayer.style.top = (layerPosition - 5) + "px";
setTimeout("showLayer()", 20);
}
}
function hideLayer() {
var hiddenLayer = document.getElementById("mainmenu");
var layerPosition = parseInt(hiddenLayer.style.top);
if (layerPosition <= 315) {
hiddenLayer.style.top = (layerPosition + 5) + "px";
setTimeout("hideLayer()", 20);
}
}
Notice on the fourth line of the hideLayer function, I have the condition set to <= 315, this is due to the fact that setting it equal to 315 causes the element to move only a few pixels in either direction after clicking the trigger element. Here's the HTML elements I have dedicated to the animation:
<div id="mainbutton" onclick="showLayer('mainmenu'); hideLayer('mainmenu')"></div>
<div id="mainmenu" style="position: absolute; top: 690px; left: 9px;"
onclick="showLayer('mainmenu')"> </div>
And here are the styles for them:
div#mainmenu { width: 600px; height: 350px; border-style: solid; background-color:
rgb(0, 0, 0) ; border-width: 3px; border-top-right-radius: 7px; border-top-left-
radius: 7px; }
div#mainbutton { position: absolute; top: 674px; left: 12px; width: 28px; height:
28px; border-style: solid; border-color: rgb(255, 255, 255); border-width: 1px; border-
radius: 4px; }
And the fiddle : http://jsfiddle.net/JAtLA/
I had to put some of the styles inline with the HTML because the animation wouldn't work any other way. At first I thought the problem had solely lain in the if conditional of the hideLayer function. But after tweaking it I'm not so sure now.

I don't know if it's what you want but here is my answer :
There is a problem of logic in your code. You wrote
if(layerPosition<=315){
hiddenLayer.style.top = (layerPosition + 5) + "px";}
It means that if the top is 315 or less, the top will increase until it arrives to 316. But in the first function, you say it to stop at 315. So the function hideLayer will just get it moving from 1 pixel.
The solution is to tell him <400 instead of <=315 (or something higher than 400).
Here is a modified fiddle : http://jsfiddle.net/7egr7/2/

It looks like "hideLayer" will stop if (layerPosition <= 315). Is that really what you want? It happens after 1 iteration.
Note that the y axis goes down the screen (i.e. zero is at the top).
Clicking the button will call showLayer, and then hideLayer.
If the menu is open (i.e. layerPosition > 315), showLayer will not do anything (i guess that is what you intend), and hideLayer will make the menu go up by 5 (from 315 to 320).
On the next iteration of hideLayer (layerPosition <= 315) will be false, so it will not do anything.
Try this:
var open = false;
function showLayer() {
if (open)
return;
var hiddenLayer = document.getElementById("mainmenu");
var layerPosition = parseInt(hiddenLayer.style.top);
if (layerPosition > 315) {
hiddenLayer.style.top = (layerPosition - 5) + "px";
setTimeout("showLayer()", 20);
}
else {
open = true;
}
}
function hideLayer() {
if (!open)
return;
var hiddenLayer = document.getElementById("mainmenu");
var layerPosition = parseInt(hiddenLayer.style.top);
if (layerPosition <= 685) {
hiddenLayer.style.top = (layerPosition + 5) + "px";
setTimeout("hideLayer()", 20);
}
else {
open = false;
}
}
In the html, I would like to check if the thing is open or closed before doing anything.
<div id="mainbutton" onclick="if (!open) { showLayer('mainmenu'); } else { hideLayer('mainmenu'); }">
but layerPosition <= 685 is the only change that really matters.

Related

element not appends in body on window onload

I have been created the function which detects the screen zoom-in or zoom-out function. I am trying if window zoom == 100 or is in normal size the notification will remove else it append instantly.
In my code, it's working perfectly but it not working on window load, for showing the demo and result I have to click ctrl+ or ctrl-.
I am trying as window load it auto decide and append if window zoom, not 100 or normal.
Please help me with how I fix this?
function informationbar(percentage, zoomstatus) {
$("body").append('<div id="informationbar" style="top: 0px;"><img src="#" style="width: 14px; height: 14px; float: right; border: 0; margin-right: 5px" />You are using the window screen on ' + percentage + '% ' + zoomstatus + ' resolution, might some options are not visible properly on this current resolution please fit the screen on 100% as this our highly recommendation.</div>');
}
$(window).resize(function() {
var browserZoomLevel = Math.round(window.devicePixelRatio * 100);
if (browserZoomLevel !== '100') {
if (browserZoomLevel > "100") {
var status = "ZoomIn";
} else {
var status = "ZoomOut";
}
informationbar(browserZoomLevel, status);
} else {
$("div#informationbar").remove();
}
});
var browserZoomLevel = Math.round(window.devicePixelRatio * 100);
if (browserZoomLevel == '100') {
$("div#informationbar").remove();
} else {
if (browserZoomLevel > "100") {
var status = "ZoomIn";
} else {
var status = "ZoomOut";
}
informationbar(browserZoomLevel, status);
}
#informationbar {
position: fixed;
left: 0;
width: 100 %;
text - indent: 5 px;
padding: 5 px 0;
background - color: lightyellow;
border - bottom: 1 px solid black;
font: bold 12 px Verdana;
}
* html# informationbar {
/*IE6 hack*/
position: absolute;
width: expression(document.compatMode=="CSS1Compat" ? document.documentElement.clientWidth + "px": body.clientWidth + "px");
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
You seem to be using !== to compare numbers and strings, e.g. browserZoomLeveL !== '100' where browserZoomLevel = Math.round(...).
That will always give false, since the a string isn't a number, and === is strict about types. You should replace === '100' with just === 100.

How to force div to not go out from another

Problem is simple but seems I can't get over it, div called ".player" shouldn't be going out from div ".play-ground", it should be moving only in its yellow space. Next thing which I'm trying to achieve is that I want a div same size of the red one, showing up for some time, so that the user can catch it with the red one and after that he gets points otherwise doesn't. Is there any way to do it? And how make div disapear after being catched?
var a = prompt("Provide nick");
while (a === "") {
a = prompt("Provide nick");
}
document.write("<p>Nick: " + a + "</p>");
/* -------- */
var ground = document.getElementsByClassName('play-ground')[0];
var player = document.getElementsByClassName('player')[0];
var points = document.getElementsByClassName('numba')[0];
var thing = document.getElementsByClassName('thing-tocatch')[0];
document.onkeydown = move;
var lefts = 0;
var tops = 0;
function move(e) {
console.log(e.keyCode);
if (e.keyCode == 68) {
lefts += 100;
player.style.left = lefts + "px";
points.innerHTML = lefts;
}
if (e.keyCode == 65) {
lefts -= 100;
player.style.left = lefts + "px";
}
if (e.keyCode == 83) {
tops += 100;
player.style.top = tops + "px";
}
if (e.keyCode == 87) {
tops -= 100;
player.style.top = tops + "px";
}
}
.play-ground {
position: relative;
background: yellow;
width: 800px;
height: 700px;
}
.player {
position: absolute;
background: red;
width: 100px;
height: 100px;
}
.thing-tocatch {
background: blue;
height: 100px;
width: 100px;
position: absolute;
margin: 200px 200px;
}
<div id="game">
<div class="points">
<h3>Points: <span class="numba">0</span></h3>
</div>
<div class="play-ground">
<div class="thing-tocatch">
</div>
<div class="player">
</div>
</div>
</div>
</div>
I cannot write whole the app here, but I just want to show you some things.
Try to write your code: one action - one function. You can see as I did. I've splitted up your move function on two: onKeyDown and movePlayer. It will help you to support your code when the app will become bigger.
You should store states of your subjects. For example I've created object Palyer where I store his coords (you used for that two vars: lefts and tops). It will be better if you will implement the same for all subjects in your app. For example, the Player has props: width, height, x, y, color. The ground has props: width, height, color. The thing also should have props as for player. You should store these states as global variables, because you will need to use them in different functions.
Your questions:
Next thing which I'm trying to achieve is that I want a div same size of the red one, showing up for some time, so that the user can catch it with the red one and after that he gets points otherwise doesn't. Is there any way to do it?. Your question contains answer. You need a function which will draw (document.createElement('div')) HTML element and after that you will be able to change its styles. OR you can create the thing before start (as you did with player) and keep it hidden (style display: none;)
And how make div disapear after being catched? You can remove thing from DOM or change style to display: none;
I advice you to find similar apps to check how other developers implement similar things:
Pong Clone In JavaScript
Snake Game in vanilla js
var a = prompt("Provide nick");
while (a === "") {
a = prompt("Provide nick");
}
document.write("<p>Nick: " + a + "</p>");
/* -------- */
var ground = document.getElementsByClassName('play-ground')[0];
var player = document.getElementsByClassName('player')[0];
var points = document.getElementsByClassName('numba')[0];
var thing = document.getElementsByClassName('thing-tocatch')[0];
document.onkeydown = onKeyDown;
var Player = {x: 0, y: 0};
var STEP = 100;
function onKeyDown (e) {
console.log(e.keyCode);
var x = Player.x;
var y = Player.y;
if (e.keyCode == 68) {
x += STEP;
}
if (e.keyCode == 65) {
x -= STEP;
}
if (e.keyCode == 83) {
y += STEP;
}
if (e.keyCode == 87) {
y -= STEP;
}
movePlayer(x, y);
}
function movePlayer (x, y) {
if (!isCoordsInsideGround(x, y)) return;
Player.x = x || 0;
Player.y = y || 0;
player.style.left = Player.x + "px";
player.style.top = Player.y + "px";
}
function isCoordsInsideGround (x, y) {
if (x < 0 || ground.offsetWidth - STEP < x) {
return false;
}
if (y < 0 || ground.offsetHeight - STEP < y) {
return false;
}
return true;
}
.play-ground {
position: relative;
background: yellow;
width: 800px;
height: 700px;
}
.player {
position: absolute;
background: red;
width: 100px;
height: 100px;
}
.thing-tocatch {
background: blue;
height: 100px;
width: 100px;
position: absolute;
margin: 200px 200px;
}
<div id="game">
<div class="points">
<h3>Points: <span class="numba">0</span></h3>
</div>
<div class="play-ground">
<div class="thing-tocatch">
</div>
<div class="player">
</div>
</div>
</div>
</div>

Drawing lines using RequestAnimationFrame()

I want to draw a horizontal line when the game launches and was able to come up with something that drew the line using requestAnimationFrame() and ctx.stroke().
The problem is that when I attempt to edit the length of the line by changing the values of the end point on the line, the line remains the same length.
If anyone could take a look at it and explain what is going on I would really appreciate it.
var canvasTop = document.getElementById('top');
var ctxTop = canvasTop.getContext('2d');
var frameCountTop = 0;
var fpsTop, fpsIntervalTop, startTimeTop, nowTop, thenTop, elapsedTop;
function startAnimatingTop(fpsTop) {
fpsIntervalTop = 1000 / fpsTop;
thenTop = Date.now();
startTimeTop = thenTop;
drawTop();
}
var topLinePointA = [32, 80];
var topLinePointB = [280, 80];
var topLineStart = topLinePointA[0];
var topLineIncrement = topLineStart + 1;
var topLineEnd = topLinePointB[0];
function drawTop() {
var i = 32;
while (i < topLineEnd) {
requestAnimationFrame(drawTop);
i++;
nowTop = Date.now();
elapsedTop = nowTop - thenTop;
if (elapsedTop > fpsIntervalTop && i < topLineEnd) {
thenTop = nowTop - (elapsedTop % fpsIntervalTop);
ctxTop.lineWidth = 20;
ctxTop.strokeStyle = "black";
ctxTop.moveTo(topLineStart, 80);
ctxTop.lineTo(topLineIncrement, 80);
ctxTop.stroke();
topLineStart += 1;
} else {
cancelAnimationFrame(drawTop);
return;
}
}
}
startAnimatingTop(100);
/*HANGMAN STYLES*/
/*CLASS SELECTORS*/
.lineContainer {
/*border-style: solid;
border-color: blue;*/
}
#top {
position: absolute;
height: 5%;
width: 45%;
left: 30%;
}
#side {
position: absolute;
bottom: 20%;
left: 70%;
height: 78%;
width: 5%;
}
#bottom {
position: absolute;
bottom: 35%;
height: 5%;
width: 56%;
left: 20%;
}
#hangman {
position: absolute;
left: 30%;
height: 40%;
width: 10%;
}
<canvas id='top' class='lineContainer'></canvas>
<canvas id='side' class='lineContainer'></canvas>
<canvas id='bottom' class='lineContainer'></canvas>
<canvas id='hangman' class='lineContainer'></canvas>
<canvas id='puzzle'></canvas>
<div id='scorecard'>
</div>
There are many problems with your code.
You need to read up on using the canvas. https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D will help.
Only call requestAnimationFrame once per frame. Putting it inside a while loop will just start 1000's of frames fighting for display refresh.
Start paths with ctx.beginPath();
Clear the canvas using ctx.clearRect(0,0,width,height)
Set canvas size via attributes not via style properties.
The first argument to the function called by requestAnimationFrame is the time. eg drawTop(time)
See comments for more info.
ctx.canvas.width = 100; // << set the canvas size via canvas attributes not style
ctx.canvas.height = 100;
var thenTop = performance.now(); // to get time.
requestAnimationFrame(drawTop); // <<< start the render loop with request, dont call direct
function drawTop(nowTop) { // << time passed to render call
requestAnimationFrame(drawTop); // <<< put call here not in loop
ctxTop.clearRect(0, 0, ctxTop.canvas.width, ctxTop.canvas.height); // <<< clear the canvas
var i = 32;
while (i < topLineEnd) {
// requestAnimationFrame(drawTop); // <<<<<<< Not here
i++;
elapsedTop = nowTop - thenTop;
if (elapsedTop > fpsIntervalTop && i < topLineEnd) {
thenTop = nowTop - (elapsedTop % fpsIntervalTop);
ctxTop.lineWidth = 20;
ctxTop.strokeStyle = "black";
ctxTop.beginPath(); // <<<<<< To start a new path
ctxTop.moveTo(topLineStart, 80);
ctxTop.lineTo(topLineIncrement, 80);
ctxTop.stroke();
topLineStart += 1;
} else {
return;
}
}
}

Unexpected NaN value when parsing the attribute on after content + z-index

I have a really weird issue, here it is :
i wanted to create a perspective shadow like this topic (::after instead in my case) How to create a perspective shadow with CSS?
div {
position: relative;
display: inline-block;
height: 150px;
width: 150px;
background: url(//placehold.it/150x150);
margin-left: 30px;
}
div::before {
content: "";
position: absolute;
z-index: -1;
bottom: 0;
left: 15px;
height: 10%;
width: 70%;
box-shadow: -25px -4px 4px 0 rgba(0,0,0,0.75);
transform: skewX(60deg);
}
and then when i load my webpage and then i click on "inspect element" from firefox and click on something in the code, i've got this issue "Unexpected NaN value when parsing the attribute", i searched on forum and people said that it may be a Qjery problem but when i delete this ::after everything is good.
here is my Javascript file:
function styleTabHover(tabButton){
tabButton.style.color= "#ff9900";
}
function styleTabOut(tabButton){
tabButton.style.color= "white";
tabButton.style.borderColor= "white";
}
function check_email(ev){
var champ = ev.currentTarget;
if(!champ.value.includes("#")){
champ.style.outline = "2px dotted red";
document.getElementById("champ_requis").style.opacity = "1";
}else{
champ.style.outline = "none";
document.getElementById("champ_requis").style.opacity = "0";
}
}
function changeTab(idbouton){
var tabs = document.getElementsByClassName("menu_bouton");
console.log(tabs,"changetab fonction lancé")
var i;
for (i=0;i<tabs.length;i++){
tabs[i].style.backgroundColor = "initial";
tabs[i].style.zIndex = "0";
tabs[i].onmouseover = function(){styleTabHover(this)};
tabs[i].onmouseout = function(){styleTabOut(this)};
}
var bouton = document.getElementById(idbouton);
bouton.style.background = "#ff9900";
bouton.style.color = "white";
bouton.onmouseover= function(){this.style.cursor = "default"};
}
var imgPositionMoins = 0;
function style_projet_slide(droite){
var lst_projetImg = document.getElementsByClassName("projets_img");
var i;
if(droite && (imgPositionMoins > (-100*(lst_projetImg.length-1)) ) ){
imgPositionMoins -= 100;
for(i=0;i<lst_projetImg.length;i++){
lst_projetImg[i].style.left = imgPositionMoins+"%";
}
}else if ( !droite && imgPositionMoins < 0){
imgPositionMoins += 100;
for(i=lst_projetImg.length-1; i>=0; i--){
lst_projetImg[i].style.left = imgPositionMoins+"%";
}
}
}
function projet_desc(indice){
var lst_desc=document.getElementById("projet_desc").children;
var i;
for (i=0;i<lst_desc.length;i++){
if (i==indice){
lst_desc[i].style.display = "block";
} else{
lst_desc[i].style.display = "none";
}
}
window.scroll({
top: 800,
left: 0,
behavior: 'smooth'
});
}
another problem i get, when i use z-index -1 when i load the webpage, i see the ::before content during 1 second which is supposed to be behind the main content. So, i tried to use a positive z-index as people said but it doesnt work when i put a higher z-index on the main content. I saw that i have to put position:relative but on the official doc. it shows that we can do an absolute position.
Can someone help me ? Thanks !

How to compare positions of two elements in javascript

I have been trying to make this work since the beginning of this week but couldn't figure it out. I have two elements in my HTML file. They are on the same vertical lane, element1 is moving 60ems to the left horizontally with each button click. I have to compare the positions of these two elements and detect whether element1 has passed the element2 with an if/else statement. When it passes I want to move the element1 to its initial position and start over. But if statement never shoots, it always jumps to else statement.
I have tried comparing following properties:
$('#elemet1').position();
$('#elemet1').position().left;
$('#elemet1').offset();
$('#elemet1').offsetLeft;
$('#elemet1').css("position");
$('#elemet1').css("left");
$('#elemet1').css("margin");
$('#elemet1').left;
I tried to compare the positions like below:
$(function () {
$("button").click(function () {
var position1 = $('#element1').css("left");
var position2 = $('#element2').css("left");
if (position1 <= position2) {
$("#element1").animate({left:'+=240em'}, 600);
}
else {
$("#element1").animate({left:'-=60em'}, 600);
}
});
});
If you can give me an answer or direct me to another post I will appreciate it. Thank you in advance.
EDIT: The style I use is below:
.element2 {
position: relative;
width: 60em;
height: 40em;
bottom: 8em;
background: rgba(242, 210, 139, 0.6);
border-radius: 1.2em;
z-index: 1;
overflow: hidden;
#element1 {
position: absolute;
margin-left: 180em;
width: 60em;
height: 40em;
z-index: 1;
}
And I should have mentioned this at the beginning: element1 is inside element2:
<div class="element2">
<img id="element1" src="image/bg1.png" />
</div>
This will give you the current position of an element:
$('#element').position().left;
If you need position relative to the document (instead of relative to a parent element) you can use:
$('#element').offset().left;
You should just be able to compare the return values of these for the different elements directly. Here's some sample code that works for me, note there is no need to parse since they always return pixel values.
var pos = Math.max($(w).scrollTop(), 38),
top = $(ballon).position().top,
dist = Math.abs(pos-top),
time = dist > 1000 ? 2000 : dist / 0.15;
if (pos + $(w).height() >= pHeight) {
pos = pHeight - bHeight - gHeight;
$(ballon).animate({'top': pos}, time, 'easeInOutSine');
}
else if (dist > 150 || pos < 100) {
$(ballon).animate({'top': pos}, time, 'easeInOutBack');
}

Categories