Move html element using JavaScript across page - javascript

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>

Related

Animating with 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>

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>

Animating back and forth based on scroll position

I have created a small demo of two boxes animating in and out based on scroll position. But this isn't exactly what I want to achieve. What I want is for the boxes to animate based on scroll position not just transition in and out when a certain point is reached.
For example the scrolling should control the animation so if you scroll down the boxes will animate in, if you scroll up they will animate out. If you stop scrolling mid animation the animation will stop. If you reverse the scroll position the animation will reverse. So the animation only happens as you scroll.
I hope that is clear enough for you to understand. I will try provide a link to what I am trying to achieve. But for now here's my demo just using a transition to animate the boxes.
jQuery(document).ready(function($){
var scroll_pos = $(window).scrollTop();
var box = $('#container').offset().top - 200;
$(window).on('scroll', function(){
scroll_pos = $(window).scrollTop();
$('p').html(scroll_pos);
if(scroll_pos >= box){
$('#left').addClass('animate');
$('#right').addClass('animate');
}else{
$('#left').removeClass('animate');
$('#right').removeClass('animate');
}
});
});
#container{
width: 600px;
height: 300px;
margin: 1000px auto;
overflow: hidden;
font-size: 0;
}
#left{
width: 55%;
height: 300px;
background-color: blue;
display: inline-block;
transform: translateX(-100%);
transition: all 0.5s;
}
#right{
width: 45%;
height: 300px;
background-color: yellow;
display: inline-block;
transform: translateX(100%);
transition: all 0.5s;
}
#left.animate{
transform: translateX(0%);
}
#right.animate{
transform: translateX(0%);
}
p{
position: fixed;
top: 0;
left: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<p></p>
<div id="container">
<div id="left"></div>
<div id="right"></div>
</div>
Here's an example of what I want to achieve. As you can see the scroll controls the animation of the fidget spinner https://ampbyexample.com/visual_effects/basics_of_scrollbound_effects/
Based on this answer you could do someting like:
/**
* inViewport jQuery plugin by Roko C.B.
* http://stackoverflow.com/a/26831113/383904
* Returns a callback function with an argument holding
* the current amount of px an element is visible in viewport
* (The min returned value is 0 (element outside of viewport)
*/
;(function($, win) {
$.fn.inViewport = function(cb) {
return this.each(function(i,el) {
function visPx(){
var elH = $(el).outerHeight(),
H = $(win).height(),
r = el.getBoundingClientRect(), t=r.top, b=r.bottom;
return cb.call(el, Math.max(0, t>0? Math.min(elH, H-t) : Math.min(b, H)));
}
visPx();
$(win).on("resize scroll", visPx);
});
};
}(jQuery, window));
// Now our stuff:
var $container = $("#container");
var $left = $("#left");
var $right = $("#right");
$container.inViewport(function( px ) {
var v = 1 - px / $container.height(); // Value from 1.0 to 0.0 and v.versa
$("p").text(v);
$left.css({transform: `translateX(${ -v * 100 }%)`});
$right.css({transform: `translateX(${ v * 100 }%)`});
});
body {
height: 500vh;
}
#container {
position: relative;
margin: 0 auto;
top: 200vh;
overflow: hidden;
width: 60vw;
height: 60vh;
}
#left,
#right {
width: 50%;
height: 100%;
float: left;
}
#left {
background-color: blue;
transform: translateX(-100%);
}
#right {
background-color: yellow;
transform: translateX(100%);
}
p {position: fixed; top:0; left: 0;}
<div id="container">
<div id="left"></div>
<div id="right"></div>
</div>
<p></p>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

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>

Changing CSS Div Position Value Given in % Using Javascript

I want to be able to click a button and change a div value given in % to move the div off screen at the click of a button.
However, the code below produces no result when the button is clicked. I really appreciate any advice I can get.
function Shift() {
var x = document.getElementById("Lac");
if (x.style.left === "0%" && x.style.top === "0%") {
x.style.left = "100%";
x.style.top = "100%";
}
}
#Lac {
position: absolute;
width: 100%;
height: 100%;
z-index: 2;
left: 0%;
top: 0%;
background-color: #0062FF;
transition-duration: 0.3s;
}
<div id="Lac">
<button onclick="Shift()">Button</button>
</div>
Solution 1: I suggest you remove the if-statement. It doesn't do any good.
function Shift() {
var x = document.getElementById("Lac");
x.style.left = "100%";
x.style.top = "100%";
}
#Lac {
position: absolute;
width: 100%;
height: 100%;
z-index: 2;
left: 0%;
top: 0%;
background-color: #0062FF;
transition-duration: 0.3s;
}
<div id="Lac">
<button onclick="Shift()">Button</button>
</div>
Solution 2: Add a className instead of all that JavaScript.
#Lac {
position: absolute;
width: 100%;
height: 100%;
z-index: 2;
left: 0%;
top: 0%;
background-color: #0062FF;
transition-duration: 0.3s;
}
#Lac.hide {
left: 100%;
top: 100%;
}
<div id="Lac">
<button onclick="this.parentNode.className='hide';">Button</button>
</div>
You cannot retrieve the value from .style.left you need to do the following:
var style = window.getComputedStyle(document.getElementById("Lac"))
console.log(style.left); //outputs 0px
var left = parseInt(style.left); //0
if ( !left ){
//do the animation
}

Categories

Resources