I am trying to make a square move back and forth by pressing a button one time with javascript. I can make it move to the right edge but don't know how to make it move back again.
Help appreciated.
function myMove() {
let id = null;
const elem = document.getElementById("animate");
let pos = 0;
clearInterval(id);
id = setInterval(frame, 5);
function frame() {
if (pos == 350) {
clearInterval(id);
} else {
pos++;
elem.style.left = pos + "px";
}
}
}
#container {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#animate {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
<body>
<p><button onclick="myMove()">Click Me</button></p>
<div id ="container">
<div id ="animate"></div>
</div>
I know you are asking for a javascript-based solution, but it's worth noting that this kind of presentation can be achieved with CSS alone.
So, for the sake of completeness, I am posting a CSS-only solution below.
N.B. There is a key difference between what CSS is capable of and what JS is capable of.
Note that in the CSS-only example below, each time you click the button, you will then have to click outside the button before the button will work again.
CSS-only Working Example:
.move-square-button {
display: block;
margin-bottom: 12px;
cursor: pointer;
}
.container {
width: 400px;
height: 144px;
position: relative;
background-color: yellow;
}
.square {
position: absolute;
top: 0;
left: 0;
width: 50px;
height: 50px;
background-color: red;
transform: translateX(0);
}
.move-square-button:focus {
cursor: not-allowed;
}
.move-square-button:focus + .container .square {
animation: moveSquareRightThenLeft 2s linear;
}
#keyframes moveSquareRightThenLeft {
50% { transform: translateX(calc(400px - 100%)); }
}
<button class="move-square-button" type="button">Click Me</button>
<div class="container">
<div class="square"></div>
</div>
Not the prettiest solution but shoud do the trick. Essentially if the rectangle reaches the right edge the "inverseDirection" variable inverts from false to true and therefore the pos variable decrements instead of increment. The opposite happens in the left edge.
function myMove() {
let id = null;
const elem = document.getElementById("animate");
let pos = 0;
let inverseDirection = false;
clearInterval(id);
id = setInterval(frame, 5);
function frame() {
if (pos === 350 && !inverseDirection) {
inverseDirection = true;
}else if(pos === 0 && inverseDirection){
inverseDirection = false;
}
pos = (inverseDirection) ? pos-1 : pos+1;
elem.style.left = pos + "px";
}
}
#container {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#animate {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
<p><button onclick="myMove()">Click Me</button></p>
<div id ="container">
<div id ="animate"></div>
</div>
whenever you are calling the myMove function it has pos set to 0. you should calculate position on the fly, and based on that logic you will be moving it right or left. assume the length is 350, you can do something like this:
function myMove() {
let id = null;
const elem = document.getElementById("animate");
let pos = elem.offsetLeft;
let dir = "";
if(pos === 0) {
dir = "right";
} else {
dir = "left";
}
clearInterval(id);
id = setInterval(frame, 5);
function frame() {
if (pos == 350 && dir == "right") {
clearInterval(id);
} if (pos == 0 && dir == "left") {
clearInterval(id);
} else if(dir === "right") {
pos++;
elem.style.left = pos + "px";
} else if(dir === "left") {
pos--;
elem.style.left = pos + "px";
}
}
}
#container {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#animate {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
<body>
<p><button onclick="myMove()">Click Me</button></p>
<div id ="container">
<div id ="animate"></div>
</div>
Not sure if this is exactly what you wanted but below code will animate the red block to move back and forth once every time you click the button.
Basically you just maintain a variable that stores the direction of movement. So here you set forward to true if its moving forwards and false if backwards. And based on the direction i.e value of forward, you either increase the value of pos or decrease it.
Now if the block is moving forward and the position is 350, set forward to false.
And finally when the direction is not forward and the position is 0, you clear the interval to end the animation, as the block reached back to initial position.
function myMove() {
let id = null;
const elem = document.getElementById("animate");
let pos = 0;
id = setInterval(frame, 5);
let forward = true;
function frame() {
if(!pos && !forward) {
clearInterval(id);
forward = true;
return;
}
if(pos == 350 && forward) {
forward = false;
}
forward ? pos++ : pos--;
elem.style.left = pos + "px";
}
}
#container {
width: 400px;
height: 400px;
position: relative;
background: yellow;
}
#animate {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
<body>
<p><button onclick="myMove()">Click Me</button></p>
<div id ="container">
<div id ="animate"></div>
</div>
Related
I created slider having 5 slides.
It's actually mouse wheel scroll horizontal slider, But I want that there should be option to use of keyboard left and right arrow keys to scroll slides. I do some below jquery that works.
But when I press left arrow key at 6th time, last (5th) slide goes left and blank screen show. And same for right arrow key. I expect when I press left arrow key at 6th time,
it should not work or last slide not move to left. Please help me to solve this.
Please see My codepen
jquery
$('body').keydown(function(e) {
if(e.keyCode == 37) { // left
$('.slide').animate({
left: '-=' + $('.slide').innerWidth()
});
}
else if(e.keyCode == 39) { // right
$('.slide').animate({
left: '+=' + $('.slide').innerWidth()
});
}
});
I tried to reproduce your example , to achieve key event
you should know that I've added a condition to prevent extra scroll , so your slide will scroll by using exactly the width of slides ;
if($(this).is(':animated')) return;
also I've added scroll using key arrow :
see below snippet :
$('.slide-container').on('mousewheel DOMMouseScroll', function(event) {
if ($(this).is(':animated')) return;
var delta = Math.max(-1, Math.min(1, (event.originalEvent.wheelDelta || -event.originalEvent.detail)));
$(this).animate({
scrollLeft: ($(this).scrollLeft() - (delta * $('.slide').innerWidth()))
}, 200);
event.preventDefault();
var $numbers = $('.indicator').children();
//check delta value 1 or -1
var count = (delta == -1) ? $(".indicator .active").index() + 1 : $(".indicator .active").index() - 1;
//if count is less then divs and not -1
if (count < $('.indicator').children().length && count != -1) {
//add active class there
$numbers.eq(count).addClass('active').siblings().removeClass('active');
}
});
$('body').keydown(function(e) {
if ($(".slide-container").is(':animated')) return;
var $indicators = $('.indicator').children();
var count = -1;
if (e.keyCode == 37) { // left
$(".slide-container").animate({
scrollLeft: $(".slide-container").scrollLeft() + ($('.slide').innerWidth())
}, 200);
count = $(".indicator .active").index() + 1
} else if (e.keyCode == 39) { // right
$(".slide-container").animate({
scrollLeft: $(".slide-container").scrollLeft() + (-$('.slide').innerWidth())
}, 200);
count = $(".indicator .active").index() - 1
}
if (count < $('.indicator').children().length && count != -1) {
//add active class there
$indicators.eq(count).addClass('active').siblings().removeClass('active');
}
});
body {
font-family: 'Roboto', sans-serif;
overflow: hidden;
border: 1px solid black;
}
* {
margin: 0;
padding: 0;
}
.header {
position: fixed;
width: 100%;
text-align: center;
background: yellow;
}
.horizontal-scroll-section {
width: 100%;
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding-top: 50px;
}
.slide-container {
display: flex;
width: 90%;
height: 80%;
overflow-x: hidden;
scroll-snap-type: X proximity;
}
.slide {
flex: 0 0 100%;
height: 100%;
font-size: 36px;
}
.slide:nth-child(odd) {
background: red;
}
.slide:nth-child(even) {
background: blue;
}
.indicator {
position: absolute;
top: 50%;
left: 10px;
color: black;
}
.indicator div {
opacity: .5;
}
.indicator div.active {
opacity: 1;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="continer">
<div class="header">
<h1 class="title"> Horizontal Scrolling </h1>
<span>(Use Mousewheel)</span>
</div>
<div class="horizontal-scroll-section">
<div class="slide-container">
<div class="slide">A</div>
<div class="slide">B</div>
<div class="slide">C</div>
<div class="slide">D</div>
<div class="slide">E</div>
</div>
</div>
<span class="indicator">
<div class="active">─</div>
<div>─</div>
<div>─</div>
<div>─</div>
<div>─</div>
</span>
</div>
<!--continer ends here-->
<style>
#container {
width: 400px;
height: 400px;
position: relative;
background: rgb(240, 240, 231);
}
#animate {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
#animate1 {
width: 50px;
height: 50px;
left: 350px;
top: 2px;
position: absolute;
background-color: rgb(43, 1, 1);
}
</style>
<p>
<button onclick="myMove()">Click Me</button>
</p>
<div id="container">
<div id="animate"></div>
<div id="animate1"></div>
</div>
<script>
function myMove() {
var elem = document.getElementById("animate");
var elem1 = document.getElementById("animate1");
var pos = 0;
var pos1 = 0;
var id = setInterval(frame, 5);
var id1 = setInterval(frame1, 5);
function frame() {
if (pos == 350) {
clearInterval(id);
} else {
pos++;
elem.style.top = pos + "px";
elem.style.left = pos + "px";
}
}
function frame1() {
if (pos1 == 350) {
clearInterval(id1);
} else {
pos1++;
elem1.style.top = pos1 + "px";
elem1.style.right = pos1 + "px";
}
}
}
</script>
In the above code I have 2 cubes(div). On click of button, the left cube should move from left to right till the end of the container diagonally and right cube should move from right to left diagonally till the end of the container. But only left cube is moving from left to right and right cube is moving from top to bottom. I want right cube to be moved from right to left diagonally till the end of the container. And this is my sandbox link. https://codesandbox.io/s/autumn-sun-uz961?file=/index.html
.animate1 class has left:350px make it to right:0 it will work.
function myMove() {
var elem = document.getElementById("animate");
var elem1 = document.getElementById("animate1");
var pos = 0;
var pos1 = 0;
var id = setInterval(frame, 5);
var id1 = setInterval(frame1, 5);
function frame() {
if (pos == 350) {
clearInterval(id);
} else {
pos++;
elem.style.top = pos + "px";
elem.style.left = pos + "px";
}
}
function frame1() {
if (pos1 == 350) {
clearInterval(id1);
} else {
pos1++;
elem1.style.top = pos1 + "px";
elem1.style.right = pos1 + "px";
}
}
}
#container {
width: 400px;
height: 400px;
position: relative;
background: rgb(240, 240, 231);
}
#animate {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
#animate1 {
width: 50px;
height: 50px;
right:0px;
position: absolute;
background-color: rgb(43, 1, 1);
}
<p>
<button onclick="myMove()">Click Me</button>
</p>
<div id="container">
<div id="animate"></div>
<div id="animate1"></div>
</div>
Update your css and change left: 350px; to right: 0px; for #animate1 :
function myMove() {
var elem = document.getElementById("animate");
var elem1 = document.getElementById("animate1");
var pos = 0;
var pos1 = 0;
var id = setInterval(frame, 5);
var id1 = setInterval(frame1, 5);
function frame() {
if (pos == 350) {
clearInterval(id);
} else {
pos++;
elem.style.top = pos + "px";
elem.style.left = pos + "px";
}
}
function frame1() {
if (pos1 == 350) {
clearInterval(id1);
} else {
pos1++;
elem1.style.top = pos1 + "px";
elem1.style.right = pos1 + "px";
}
}
}
#container {
width: 400px;
height: 400px;
position: relative;
background: rgb(240, 240, 231);
}
#animate {
width: 50px;
height: 50px;
position: absolute;
background-color: red;
}
#animate1 {
width: 50px;
height: 50px;
right: 0px; /* instead of right : 350px; */
top: 2px;
position: absolute;
background-color: rgb(43, 1, 1);
}
<p>
<button onclick="myMove()">Click Me</button>
</p>
<div id="container">
<div id="animate"></div>
<div id="animate1"></div>
</div>
Off Topic, but are you aware of CSS transitions?
function myMove() {
document.getElementById("animate").classList.toggle("move");
document.getElementById("animate1").classList.toggle("move");
}
// try clicking the boxes themselves
for (let item of document.querySelectorAll("#animate, #animate1")) {
item.onclick = function() {
item.classList.toggle("move");
}
}
#container {
width: 400px;
height: 400px;
position: relative;
background: rgb(240, 240, 231);
}
#animate {
width: 50px;
height: 50px;
top: 0;
left: 0;
position: absolute;
background-color: red;
transition: 3s linear;
}
#animate.move {
top: 350px;
left: 350px;
}
#animate1 {
width: 50px;
height: 50px;
right: 0px;
top: 2px;
position: absolute;
background-color: rgb(43, 1, 1);
transition: 3s linear;
}
#animate1.move {
top: 350px;
right: 350px;
}
<p>
<button onclick="myMove()">Click Me</button>
</p>
<div id="container">
<div id="animate"></div>
<div id="animate1"></div>
</div>
I'm trying to make a js progress bar which finishes after 5 seconds and then runs some code.
What I have from w3:
var i = 0;
function move() {
if (i == 0) {
i = 1;
var elem = document.getElementById("myBar");
var width = 1;
var id = setInterval(frame, 10);
function frame() {
if (width >= 100) {
clearInterval(id);
i = 0;
} else {
width++;
elem.style.width = width + "%";
}
}
}
}
move();
#myProgress {
width: 100%;
background-color: grey;
}
#myBar {
width: 1%;
height: 30px;
background-color: green;
}
<div id="myProgress">
<div id="myBar"></div>
</div>
How can I f.e. adjust its time to 5 seconds, with the animation still being smooth?
The animation need not be done in javascript. Use CSS instead for smoother performance and cleaner code.
It's generally a better idea to use CSS animations over JS, especially when they are simple. You should read more here. If you still want to do it in javascript for some reason, you should use this dedicated call for animating stuff requestAnimationFrame.
function move() {
var elem = document.getElementById("myBar");
myBar.style.width = "0%";
setTimeout(() => {
myBar.style.width = "100%";
});
setTimeout(() => {
alert("done");
/* do stuff */
}, 5000);
}
move();
#myProgress {
width: 100%;
background-color: grey;
}
#myBar {
width: 0%;
height: 30px;
background-color: green;
transition: width 5s linear; /* note this line */
}
<div id="myProgress">
<div id="myBar"></div>
</div>
According to docs setInterval delay param is in miliseconds
delayOptional The time, in milliseconds (thousandths of a second), the
timer should delay in between executions of the specified function or
code. See Delay restrictions below for details on the permitted range
of delay values.
var i = 0;
const element = document.getElementById("myBar");
let width = 1;
let chunk = 100 / 5;
function move() {
if (i == 0) {
let handle = setInterval(frame, 1000);
function frame() {
if (width >= 100) {
clearInterval(handle);
} else {
width = width + chunk;
element.style.width = `${width}%`;
}
}
}
}
move();
#myProgress {
width: 100%;
background-color: grey;
}
#myBar {
width: 0%;
transition: all .3s ease-in;
height: 30px;
background-color: green;
}
<div id="myProgress">
<div id="myBar"></div>
</div>
var i = 0;
function move() {
if (i == 0) {
i = 1;
var elem = document.getElementById("myBar");
var width = 1;
var id = setInterval(frame, 5000/100);
function frame() {
if (width >= 100) {
clearInterval(id);
i = 0;
} else {
width++;
elem.style.width = width + "%";
}
}
}
}
move();
#myProgress {
width: 100%;
background-color: grey;
}
#myBar {
width: 1%;
height: 30px;
background-color: green;
}
<div id="myProgress">
<div id="myBar"></div>
</div>
basicly time you want divided by count of how many loops it take to fill whole bar
For higher quality animations is better to use requestAnimationFrame.
let start;
let element = document.getElementById("myBar");
let count = 0;
function step(timestamp) {
if (start === undefined)
start = timestamp;
const elapsed = timestamp - start;
element.style.width = (100 / 2000) * elapsed + "%";
if (elapsed < 2000) { // Stop the animation after 2 seconds
window.requestAnimationFrame(step);
}else {
}
}
window.requestAnimationFrame(step);
#myProgress {
width: 100%;
background-color: grey;
}
#myBar {
width: 1%;
height: 30px;
background-color: green;
}
<div id="myProgress">
<div id="myBar"></div>
</div>
You need to change var id = setInterval(frame, 10); 1000 = 1 second
var i = 0;
function move() {
if (i == 0) {
i = 1;
var elem = document.getElementById("myBar");
var width = 1;
var id = setInterval(frame, (5*1000)/100);
function frame() {
if (width >= 100) {
clearInterval(id);
i = 0;
} else {
width++;
elem.style.width = width + "%";
}
}
}
}
move();
#myProgress {
width: 100%;
background-color: grey;
}
#myBar {
width: 1%;
height: 30px;
background-color: green;
}
<div id="myProgress">
<div id="myBar"></div>
</div>
Actually I am trying to make this type of effect using javascript, need some help how to implement it.
View Images from here:-
https://ibb.co/2c9y9jV
https://ibb.co/Jpqk3xr
My code:
function move(e) {
console.log("mouse location:", e.clientX, e.clientY);
let x = e.clientX - 520;
let y = e.clientY - 210;
let ele = document.getElementsByClassName('after')[0];
ele.style.transform = "translate3d(" + x + "px," + y + "px,0px)"
}
var temp = false;
function toggle() {
temp = !temp;
if (temp) {
let ele = document.getElementsByClassName('after')[0];
ele.style.display = 'block';
} else {
let ele = document.getElementsByClassName('after')[0];
ele.style.display = 'none';
}
}
img {
z-index: 100;
}
.after {
position: absolute;
left: 0;
bottom: 0;
border-radius: 50%;
width: 20%;
height: 20%;
display: block;
background: white
}
.image-container {
margin: 0 auto;
position: relative;
overflow: hidden;
width: max-content;
height: max-content;
}
<button onclick="toggle()">Toggle</button>
<div class="image-container">
<img onmousemove="move(event)" src="http://lorempixel.com/300/200" />
<div class="after">
</div>
</div>
I couldn't be able to make effect like image
When the top property of each div .js-player is between 10 and 100 the word #muteshould have the class .active added. The code below only executes the adding of .active on the last .js-active div. Where am I going wrong? Any pointer would be greatly appreciated.
const players = Array.from(document.querySelectorAll('.js-player')),
mute = document.querySelector('#mute');
window.addEventListener('scroll', function(e) {
players.forEach(function(player) {
let distance = player.getBoundingClientRect().top;
if (10 < distance && distance < 100) {
mute.classList.add('active');
} else {
mute.classList.remove('active');
}
})
});
.js-player {
height: 150px;
width: 200px;
background-color: red;
margin: 8em 2em;
}
#mute {
position: fixed;
top: 10px;
left: 10px;
}
.active {
color: green;
}
.filler {
height: 400px;
}
<div class="js-player"></div>
<div class="js-player"></div>
<div class="js-player"></div>
<div class="filler"></div>
<div id="mute">mute</div>
I think what you are wondering is why only the last .js-player determines whether or not the div has the active class?
If so, each time a scroll event happens, it loops over the players, and either add or removes the active class. So, when it gets to the last .js-player, if this last .js-player is not within the distance, it will remove the active class if another one set it, and add it if is, it will set it even if another one removed it.
What you need to do is stop checking once you have found a player within the distance required, something like:
const players = Array.from(document.querySelectorAll('.js-player')),
mute = document.querySelector('#mute');
window.addEventListener('scroll', function(e) {
var matched = false;
players.forEach(function(player) {
if (matched) return;
let distance = player.getBoundingClientRect().top;
if (10 < distance && distance < 100) {
mute.classList.add('active');
matched = true;
} else {
mute.classList.remove('active');
}
})
});
.js-player {
height: 150px;
width: 200px;
background-color: red;
margin: 8em 2em;
}
#mute {
position: fixed;
top: 10px;
left: 10px;
}
.active {
color: green;
}
.filler {
height: 400px;
}
<div class="js-player"></div>
<div class="js-player"></div>
<div class="js-player"></div>
<div class="filler"></div>
<div id="mute">mute</div>
You are setting active class on mute element on each iteration, which means that only the last element of array will matter.
Here's a working verions:
const players = Array.from(document.querySelectorAll('.js-player'));
const mute = document.querySelector('#mute');
window.addEventListener('scroll', function(e) {
var active = false;
players.forEach(function (player) {
let distance = player.getBoundingClientRect().top;
if (10 < distance && distance < 100) {
active = true;
}
});
active ? mute.classList.add('active') : mute.classList.remove('active');
});
.js-player {
height: 150px;
width: 200px;
background-color: red;
margin: 8em 2em;
}
#mute {
position: fixed;
top: 10px;
left: 10px;
}
.active {
color: green;
}
.filler {
height: 400px;
}
<div class="js-player"></div>
<div class="js-player"></div>
<div class="js-player"></div>
<div class="filler"></div>
<div id="mute">mute</div>
Cheers!