Animating with Javascript - javascript

In this code, I was trying to move the yellow box (the small box) to the right, bottom, left, and top respectively in the red box (the big box) and I have wanted to move the yellow box unendly. I have moved the yellow box to the right and bottom but couldn't move to the left and top. I couldn't understand what the problem is. How should I write this code in Javascript? Could you help me, please? I have used Visual Studio Code.
window.onload = function(){
var posX = 0,posY =0, posZ=0;
var smallbox = document.getElementById("smallbox");
var time = setInterval(move,10);
function move(){
if(posX>=150){
if(posY>=150){
if(posZ>=150){
clearInterval(time);
}
else{
posZ++;
smallbox.style.right = posZ + "px";
}
}
else{
posY++;
smallbox.style.top = posY + "px";
}
}
else{
posX = posX+1;
smallbox.style.left = posX + "px";
}
}
}
#bigbox{
height: 200px;
width: 200px;
background-color: red;
position: relative;
}
#smallbox{
height: 50px;
width: 50px;
background-color: yellow;
position: absolute;
}
<div id="bigbox">
<div id="smallbox">
</div>
</div>

The reason that your animation is not working is that CSS alignments for objects must use "top" or "bottom" and "left" or "right" to align themselves. What you are doing is aligning horizontally using "left" and then trying to align horizontally using "right", or the same thing but around the other way.
What I would instead suggest is using code that essentially reads:
if at top-left, move right.
if at top-right, move down.
if at bottom-right, move left.
if at bottom-left, move up.
An example of this in action:
window.onload = function() {
var posX = 0,
posY = 0,
boxW = 200,
boxH = 200,
smallboxW = 50,
smallboxH = 50;
var smallbox = document.getElementById("smallbox");
var time = setInterval(move, 10);
function move() {
if (posY <= 0 && posX < boxW) {
// go right
posX++;
smallbox.style.left = posX + "px";
}
if (posX >= boxW - smallboxW && posY < boxH) {
// go down
posY++;
smallbox.style.top = posY + "px";
}
if (posY >= boxH - smallboxH && posX > 0) {
// go left
posX--;
smallbox.style.left = posX + "px";
}
if (posX <= 0 && posY > 0) {
// go up
posY--;
smallbox.style.top = posY + "px";
}
}
}
#bigbox {
height: 200px;
width: 200px;
background-color: red;
position: relative;
}
#smallbox {
height: 50px;
width: 50px;
background-color: yellow;
position: absolute;
}
<body>
<div id="bigbox">
<div id="smallbox">
</div>
</div>
</body>

Instead of managing all calculations yourself, use the power of CSS in javascript with Element.animate().
This will also allow you to pause and play whenever needed.
const smallbox = document.querySelector('#smallbox');
smallbox.animate([
// keyframes
{
transform: 'translate(150px, 0px)'
},
{
transform: 'translate(150px, 150px)'
},
{
transform: 'translate(0px, 150px)'
},
{
transform: 'translate(0px, 0px)'
},
{
transform: 'translate(150px, 0px)'
},
], {
// timing options
duration: 2000,
iterations: Infinity
});
#bigbox {
height: 200px;
width: 200px;
background-color: red;
position: relative;
}
#smallbox {
height: 50px;
width: 50px;
background-color: yellow;
position: absolute;
}
<div id="bigbox">
<div id="smallbox">
</div>
</div>

One alternative option is to use the CSS keyframes to animate.
#bigbox {
height: 200px;
width: 200px;
background-color: red;
position: relative;
}
#smallbox {
height: 50px;
width: 50px;
background-color: yellow;
position: relative;
animation: move-around 4s infinite linear;
}
#keyframes move-around {
0% {
left: 0;
top: 0;
transform: translate(0%, 0%);
}
25% {
left: 100%;
top: 0;
transform: translate(-100%, 0%);
}
50% {
left: 100%;
top: 100%;
transform: translate(-100%, -100%);
}
75% {
left: 0;
top: 100%;
transform: translate(0%, -100%);
}
100% {
left: 0;
top: 0;
transform: translate(0%, 0%);
}
}
<body>
<div id="bigbox">
<div id="smallbox">
</div>
</div>
</body>

Related

Move html element using JavaScript across page

I am working with JavaScript to move an HTML div across the page. Below is the movement that I want the element to follow:
It should be starting and following routes 1, 2, 3 and 4. It should only change the route once the element reaches the max width/height of the page. I am using the below code and I am stuck on how to continue further.
var box = document.getElementById("box");
var height = document.getElementById("container").offsetHeight;
var widht = document.getElementById("container").offsetWidth;
window.setInterval(() => {
let addPosition = (parseInt(box.style.top) + 10);
let subPosition = (parseInt(box.style.top) - 10);
if (addPosition > height)
box.style.top = subPosition + 'px';
else
box.style.top = addPosition + 'px';
}, 100);
#container {
position: absolute;
background: purple;
width: 100%;
height: 100%;
}
#box {
position: absolute;
background: red;
width: 30px;
height: 30px;
}
<div id="container">
<div id="box" style="top: 0px; left: 0px;"></div>
</div>
No JS is needed to make this animation. You can use CSS-Animations for this.
For that, you use keyframes and change the position where the element should move to. You can define the speed with the animation-duration property and repeat it with animation-iteration-count
body {
margin: 0;
height: 100vh;
}
div {
height: 50px;
width: 50px;
background-color: red;
position: fixed;
animation-name: moveBox;
animation-duration: 5s;
animation-iteration-count: infinite;
}
#keyframes moveBox {
0% { top: 0; left: 0; }
20% { top: calc(100% - 50px); left: 0; }
50% { top: 0; left: calc(100% - 50px); }
70% { top: calc(100% - 50px); left: calc(100% - 50px); }
100% { top: 0; left: 0; }
}
<div></div>
As someone else mentioned, this is normally done with CSS animations, but if you have to use javascript you basically want a state system that keeps track of what your current target is.
Here's roughly how you could do it:
let box = document.getElementById("box");
let height = document.getElementById("container").offsetHeight;
let width = document.getElementById("container").offsetWidth;
let getAngle=function(x1,y1,x2,y2)
{
return Math.atan2(y2-y1,x2-x1);
}
let state=0;
let speed=10;//how many pixels to move per interval
let x=0,y=0;
let xTarget=0,yTarget=0;
window.setInterval(() => {
//we do not account for the box's size here, but if we needed to we could add or subtract it to the target as needed
switch(state) {
case 0:
xTarget=0;
yTarget=height;
break;
case 1:
xTarget=width;
yTarget=0;
break;
case 2:
xTarget=width;
yTarget=height;
break;
case 3:
xTarget=0;
yTarget=0;
break;
}
//do we still have more steps left? calculate the angle to the target, then step in that direction
if (state<4)
{
var angle=-getAngle(x,y,xTarget,yTarget)+Math.PI/2;
x+=Math.sin(angle)*speed;
y+=Math.cos(angle)*speed;
}
//are we close enough to the target? snap to the target, then switch to the next state
//note: you may want to calculate the actual distance here instead
if (Math.abs(xTarget-x)<speed && Math.abs(yTarget-y)<speed)
{
x=xTarget;
y=yTarget;
state++;
}
if (state>=4) state=0;//if you want the movement to loop
box.style.left=x+'px';
box.style.top=y+'px';
}, 100);
#container {
position: absolute;
background: purple;
width: 300px;
height: 200px;
}
#box {
position: absolute;
background: red;
width: 30px;
height: 30px;
}
<div id="container">
<div id="box" style="top: 0px; left: 0px;"></div>
</div>

disable scrolling untill animation is done

I have a simple animation and I want to disable scrolling on the website
until this animation is done, it should be like a loader basically
UPDATE
thank you so much, but I have an issue with that sorry for not mention because I'm using a fixed position on a container to be fixed to do smooth scrolling, so when I use 'fixed' position for any element it doesn't seem to stick in the same place here is the full code
html
<main id="app">
<div id="scroll-container" class="scroll-container">
<div class="loader">
<div class="loader__block"></div>
</div>
</div>
</main>
CSS
body {
overflow-x: hidden;
overflow-y: scroll;
background: $bg-color;
user-select: none;
font-family: 'Platform Regular';
}
#app {
overflow: hidden;
position: fixed;
height: 100vh;
width: 100vw;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.scroll-container {
position: absolute;
overflow: hidden;
z-index: 10;
display: flex;
justify-content: center;
backface-visibility: hidden;
}
.loader {
width: 100vw;
height: 100vh;
position: absolute;
z-index: 999999;
overflow: hidden;
}
.loader__block {
position: absolute;
width: 0%;
height: 100vh;
background: #111111;
animation: go-left 4s cubic-bezier(.74, .06, .4, .92) forwards;
}
#keyframes go-left {
0% {
left: 0;
width: 0%;
}
50% {
left: 0;
width: 100%;
}
100% {
left: 100%;
width: 0;
}
these containers have a fixed position and overflow hidden because I'm making smooth page transition while scrolling and moving the 'y' position
here is also the js if it's going to help
function smoothScrolling() {
const html = document.documentElement;
const { body } = document;
const scroller = {
target: document.querySelector('#scroll-container'),
ease: 0.06, // <= scroll speed
endY: 0,
y: 0,
resizeRequest: 1,
scrollRequest: 0,
};
let requestId = null;
TweenLite.set(scroller.target, {
rotation: 0.01,
force3D: true,
});
function updateScroller() {
const resized = scroller.resizeRequest > 0;
if (resized) {
const height = scroller.target.clientHeight;
body.style.height = `${height}px`;
scroller.resizeRequest = 0;
}
const scrollY = window.pageYOffset || html.scrollTop || body.scrollTop || 0;
scroller.endY = scrollY;
scroller.y += (scrollY - scroller.y) * scroller.ease;
if (Math.abs(scrollY - scroller.y) < 0.05 || resized) {
scroller.y = scrollY;
scroller.scrollRequest = 0;
}
TweenLite.set(scroller.target, {
y: -scroller.y,
});
requestId = scroller.scrollRequest > 0 ? requestAnimationFrame(updateScroller) : null;
}
function onScroll() {
scroller.scrollRequest += 1;
if (!requestId) {
requestId = requestAnimationFrame(updateScroller);
}
}
function onResize() {
scroller.resizeRequest += 1;
if (!requestId) {
requestId = requestAnimationFrame(updateScroller);
}
}
function onLoad() {
updateScroller();
window.focus();
window.addEventListener('resize', onResize);
document.addEventListener('scroll', onScroll);
}
window.addEventListener('load', onLoad);
}
Use the CSS rule position: fixed; on your div with class loader which makes it to always stay in the same place even if the page is scrolled.
as so:
.loader {
width: 100vw;
height: 100vh;
position: absolute;
z-index: 999999;
overflow: hidden;
position: fixed;
}
.loader__block {
position: absolute;
width: 0%;
height: 100vh;
background: #111111;
animation: go-left 4s cubic-bezier(.74, .06, .4, .92) forwards;
}
#keyframes go-left {
0% {
left: 0;
width: 0%;
}
50% {
left: 0;
width: 100%;
}
100% {
left: 100%;
width: 0;
}
}
<main id="app">
<div id="scroll-container" class="scroll-container">
<div class="loader">
<div class="loader__block"></div>
</div>
</div>

How to use more than one setInterval()?

I want to make the 'box' in the code move to the right and then go back to the left. I tried to use 2 setInterval but it didn't works (or maybe i don't know how to use 2 setInterval).
var box = document.getElementById("box");
var pos = 0;
var toRight = setInterval(move, 10);
function move() {
if (pos >= 150) {
clearInterval(toRight);
} else {
pos++;
box.style.left = pos + "px";
}
}
#container {
width: 200px;
height: 200px;
background-color: red;
position: relative;
}
#box {
width: 50px;
height: 50px;
background-color: blue;
position: absolute;
}
<div id="container">
<div id="box"></div>
</div>
<p id="demo"></p>
I tried so many ways and the code still doesn't run, can some one show me the way to make the 'box' move back from the right side. Thank you.
Your code was a good start, and #j08691's comment is the right direction to take it.
Use 1 interval function but keep track of which direction the box is moving and toggle it when desired.
let box = document.getElementById("box");
let pos = 0, right = true;
setInterval(() => {
pos += right * 2 - 1;
if (pos === 0 || pos === 150)
right = !right;
box.style.left = pos + "px";
}, 10);
#container {
width: 200px;
height: 200px;
background-color: red;
position: relative;
}
#box {
width: 50px;
height: 50px;
background-color: blue;
position: absolute;
}
<div id="container">
<div id="box"></div>
</div>
As an alternative you could also use css animations and skip the javascript part entirely:
#keyframes move {
from { left: 0; }
to { left: calc(100% - 50px); }
}
#container {
width: 200px;
height: 200px;
background-color: red;
position: relative;
}
#box {
width: 50px;
height: 50px;
background-color: blue;
position: absolute;
animation: move 2s linear alternate infinite;
}
<div id="container">
<div id="box"></div>
</div>
<p id="demo"></p>

How can I prevent this material ripple animation from leaking out into other div?

In the following codepen, the creator has made a material ripple effect. However there is an issue where if I add another div right next to the original the ripple will leak into it.
What should I do to change to code so that the ripple will only be contained in the div that it was activated on?
I have tried editing the JS so that the click function only activates for divs with the class ".rippleDiv" but that did not work either.
Link to codepen http://codepen.io/Ruddy/pen/09052b957d82a17bd6ca70ac6663dd6a
HTML
<div class="rippleDiv">Button</div>
<div>Button 2</div>
CSS
div {
width: 220px;
height: 120px;
background: #222;
color: #fff;
text-align: center;
line-height: 120px;
font-size: 40px;
}
/* Ripple */
.ripple {
width: 0;
height: 0;
border-radius: 50%;
background: rgba(255, 255, 255, 0.4);
transform: scale(0);
position: absolute;
opacity: 1;
}
.rippleEffect {
animation: rippleDrop .6s linear;
}
#keyframes rippleDrop {
100% {
transform: scale(2);
opacity: 0;
}
}
JS
$(".rippleDiv").click(function (e) {
// Remove any old one
$(".ripple").remove();
// Setup
var posX = $(this).offset().left,
posY = $(this).offset().top,
buttonWidth = $(this).width(),
buttonHeight = $(this).height();
// Add the element
$(this).prepend("<span class='ripple'></span>");
// Make it round!
if(buttonWidth >= buttonHeight) {
buttonHeight = buttonWidth;
} else {
buttonWidth = buttonHeight;
}
// Get the center of the element
var x = e.pageX - posX - buttonWidth / 2;
var y = e.pageY - posY - buttonHeight / 2;
// Add the ripples CSS and start the animation
$(".ripple").css({
width: buttonWidth,
height: buttonHeight,
top: y + 'px',
left: x + 'px'
}).addClass("rippleEffect");
});
The basic answer is that the 'ripple' element needs to be contained inside a div that has overflow:hidden set.
However to get this right, a number of small changes need to be made so that both the original button content, as well as the ripple itself, are correctly positioned, mainly using divs with the correct positioning attributes set.
So - here are the changes I made to get this to work: http://codepen.io/kitr/pen/xgLQpM
HTML:
<div>Button</div>
<div>Button 2</div>
CSS:
div {
width: 220px;
height: 120px;
background: #222;
color: #fff;
text-align: center;
line-height: 120px;
font-size: 40px;
position:relative;
overflow:hidden;
}
/* Ripple */
.ripple {
width: 0;
height: 0;
border-radius: 50%;
background: rgba(255, 255, 255, 0.4);
transform: scale(0);
opacity: 1;
}
.rippleEffect {
animation: rippleDrop .6s linear;
position: absolute;
}
#keyframes rippleDrop {
100% {
transform: scale(2);
opacity: 0;
}
}
Javascript:
$("div").click(function (e) {
// Remove any old one
$(".ripple").remove();
// Setup
var posX = $(this).offset().left,
posY = $(this).offset().top,
buttonWidth = $(this).width(),
buttonHeight = $(this).height();
// Add the element
$(this).append("<div class='ripple'></div>");
// Make it round!
if(buttonWidth >= buttonHeight) {
buttonHeight = buttonWidth;
} else {
buttonWidth = buttonHeight;
}
// Get the center of the element
var x = e.pageX - posX - buttonWidth / 2;
var y = e.pageY - posY - buttonHeight / 2;
// Add the ripples CSS and start the animation
$(".ripple").css({
width: buttonWidth,
height: buttonHeight,
top: y + 'px',
left: x + 'px'
}).addClass("rippleEffect");
});

Smoke Trail Effect - Javascript

How can one make a smooth smoke trail effect with Javascript, out of the code I attached? The trail should follow an object, but have the position the object had a moment ago. The code I attached does have some sort of trail effect, but it is not smooth. Can give the trail a position using something like this: position:trail = position:object, 5 ms ago?
var left = parseInt(document.getElementById("thingy").style.left);
setInterval(fly, 10);
function fly() {
if (left > 300) {
left = 300;
};
left++;
document.getElementById("thingy").style.left = left + "px";
}
setInterval(trail, 100);
function trail() {
document.getElementById("trail").style.left = left + "px";
}
<div id="thingy" style="position:absolute; top:100px; left: 0px; width: 100px; height: 100px; background-color:#000000;"></div>
<div id="trail" style="position:absolute; top:125px; left: 0px; width: 50px; height: 50px; background-color:#CCCCCC; z-index: -10;"></div>
If it is possible I would like to stay out of jQuery.
This solution clones the element each time it moves.
CSS3 transitions are used on the cloned nodes' background to simulate a smoke trail.
The code ensures there are never more than 100 cloned nodes.
var thingy= document.getElementById('thingy'),
left = thingy.offsetLeft,
shadows= [],
delta= 4;
setInterval(fly, 10);
function fly() {
var shadow= thingy.cloneNode();
shadow.classList.add('shadow');
shadow.style.backgroundColor= 'silver';
document.body.appendChild(shadow);
setTimeout(function() {
shadow.style.backgroundColor= 'white';
},100);
shadows.push(shadow);
if(shadows.length>100) {
shadows[0].parentNode.removeChild(shadows[0]);
shadows.shift();
}
if(left+delta > document.body.offsetWidth-thingy.offsetWidth || left < 0) {
delta= -delta;
}
left+= delta;
thingy.style.left = left + 'px';
}
body {
margin: 0;
padding: 0;
}
#thingy {
position: absolute;
top: 100px;
left: 0px;
width: 100px;
height: 100px;
background-color: orange;
border-radius: 50%;
}
.shadow {
transition: all 1s;
z-index: -1;
}
<div id="thingy"></div>
Update
For a "smokier" effect, you can use random values for the cloned nodes' width, height, transition, etc., like I've done in this Snippet:
var thingy= document.getElementById('thingy'),
tleft = thingy.offsetLeft,
ttop = thingy.offsetTop,
smokes= [],
deltaX= deltaY= 2;
setInterval(fly, 10);
function fly() {
if(Math.random()>0.5) {
var smoke= thingy.cloneNode();
smoke.classList.add('smoke');
smoke.style.background= 'gray';
smoke.style.opacity= 0.2;
smoke.style.transition= Math.random()+'s';
smoke.style.width= Math.random()*thingy.offsetWidth+'px';
smoke.style.height= Math.random()*thingy.offsetHeight+'px';
smoke.style.marginTop= smoke.offsetHeight+'px';
smoke.style.borderRadius= (Math.random()*25+25)+'%';
document.body.appendChild(smoke);
setTimeout(function() {
smoke.style.opacity= 0;
},100);
smokes.push(smoke);
if(smokes.length>20) {
smokes[0].parentNode.removeChild(smokes[0]);
smokes.shift();
}
}
if(tleft+deltaX > document.body.offsetWidth-thingy.offsetWidth || tleft < 0) {
deltaX= -deltaX;
}
if(ttop +deltaY > document.body.offsetHeight-thingy.offsetHeight || ttop < 0) {
deltaY= -deltaY;
}
tleft+= deltaX;
ttop += deltaY;
thingy.style.left = tleft + 'px';
thingy.style.top = ttop + 'px';
}
body {
margin: 0;
padding: 0;
background: black;
height: 100vh;
}
#thingy {
position: absolute;
top: 100px;
left: 0px;
width: 100px;
height: 100px;
background-color: orange;
border-radius: 50%;
}
.smoke {
z-index: -1;
}
<div id="thingy"></div>

Categories

Resources