I'm trying to create a square that will appear in a random place within a 300x300px space. It is currently moving horizontally but not vertically. Can someone help me get it to move vertically as well? Thank you!
#square {width: 200px;
height: 200px;
display: none;
position: relative;
}
var top=Math.random();
top=top*300;
var left=Math.random();
left=left*300;
document.getElementById("square").style.top=top+"px";
document.getElementById("square").style.left=left+"px";
Use left to translate horizontally and top for vertically.
const getRandom = (min, max) => Math.floor(Math.random()*(max-min+1)+min);
const square= document.querySelector('#square');
setInterval(() => {
square.style.left= getRandom(0, 300 - 200)+'px'; // 👈🏼 Horizontally
square.style.top = getRandom(0, 300 - 200)+'px'; // 👈🏼 Vertically
}, 500); // every 1/2 second
#space {
width: 300px;
height: 300px;
background-color: #eee
}
#square {
width: 200px;
height:200px;
position: relative;
background-color: #8e4435
}
<div id="space">
<div id="square">
</div>
</div>
If you remove the display: none it should be good, compare with this.
Also you could simplify with this:
var top = Math.random() * 300;
Related
I'm trying to position a div element over a sine wave that is used as its path. As the user scrolls, the callback should be able to calculate the left and top properties of the Ball along the sine wave. I'm having trouble with the positioning. I'm using Math.abs for the y-axis and I'm adding 8 (or -8) pixels to handle the x-axis.
Another thing I've noticed is that the scroll event listener callback sometimes missed certain breakpoints. I've console logged the scroll position and its true, the callback is either executed every ~3 pixels or the browser throttles the scroll event on its own for some reason (which I can understand, there's no point in tracking every pixel scroll).
Anyway, I'm wondering why my current approach isn't working and if there's a better solution to this problem? I feel like there's too much stuff going on and that this could be achieved in a better way. Here's what I have:
import React from "react";
import styled from "styled-components";
const lineHeight = 200;
export default React.memo(() => {
const [top, setTop] = React.useState(275);
const [left, setLeft] = React.useState(0);
const [previousPosition, setPreviousPosition] = React.useState(0);
React.useEffect(() => { const s = skrollr.init() }, []);
React.useEffect(() => {
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, [previousPosition, left]);
const handleScroll = React.useCallback(() => {
const pageYOffset = window.pageYOffset;
const isMovingForward = pageYOffset > previousPosition;
setPreviousPosition(window.pageYOffset);
setTop(lineHeight - Math.abs(lineHeight - pageYOffset));
if (isMovingForward) {
if (pageYOffset > 575 && pageYOffset <= 770) setLeft(left + 8);
} else {
if (pageYOffset <= 770 && pageYOffset >= 575) setLeft(left - 8)
}
}, [previousPosition, left]);
return (
<Main>
<Container
data-500p="transform: translateX(0%)"
data-1000p="transform: translateX(-800%)"
>
<Content>
<WaveContainer>
<Wave src="https://www.designcrispy.com/wp-content/uploads/2017/11/Sine-Wave-Curve.png" />
</WaveContainer>
<BallContainer top={top} left={left}>
<Ball />
</BallContainer>
</Content>
</Container>
</Main>
);
});
const Main = styled.div`
margin: 0;
padding: 0;
box-sizing: border-box;
`;
const Container = styled.div`
position: fixed;
width: 100%;
display: flex;
top: 0;
left: 0;
`;
const Content = styled.div`
min-width: 100vw;
height: auto;
display: grid;
place-items: center;
height: 100vh;
background: #fffee1;
font-weight: 900;
position: relative;
`;
const Wave = styled.img`
width: 600px;
`;
const WaveContainer = styled.div`
position: absolute;
left: -40px;
top: 45%;
`;
const Ball = styled.div`
width: 20px;
height: 20px;
border-radius: 50%;
background: black;
`;
const BallContainer = styled.div`
position: absolute;
transition: 0.25s;
${({ top, left }) => `top: ${top}px; left: ${left}px;`};
`;
I'm using Skrollr to handle the fixed canvas + scroll length.
Codesandbox
I changed your codesandbox so it does what you need: https://codesandbox.io/s/determined-nobel-64odf (I hope)
I should add that I changed various things about your code:
No need to set up new scroll listener every time a left or previous
position changes. What is all the code about previous position and
deciding if page is being scrolled up or down? I removed it.
The animation was being throttled due to transition: 0.25s on your
Ball container. In order to calculate the ball position relatively to
image - sinusoide, I moved them into the same container.
To calculate exact position of ball, WAVE_WIDTH and WAVE_HEIGHT
constants need to be used, and proper mathematics need to be used -
the sinusoide on image seems to be long of 2,5 periods. However 2,58
was better constant to fit the animation. I'd try using different
sinusoide and figure that out.
If you can support offset-path (not available on IE or Safari, apparently), I would strongly suggest moving as much of this as you can to CSS and SVG based animation. Here is a vanilla JS example - the only thing you actually have to calculate here is what percent along you want the animation to be, which could be based on any arbitrary scroll criteria:
const ball = document.querySelector('.ball');
window.addEventListener('scroll', () => {
const winHeight = document.body.offsetHeight;
const pageOffset = window.pageYOffset;
const pc = (pageOffset*2/winHeight)*100;
ball.style.offsetDistance = `${pc}%`;
});
* {
padding: 0;
margin: 0;
}
.page {
height: 200vh;
}
.container {
position: sticky;
top: 0;
width: 100%;
}
svg {
position: absolute;
fill: transparent;
stroke: blue;
stroke-width: 2px;
}
.ball {
offset-path: path("M10 80 C 40 10, 65 10, 95 80 S 150 150, 180 80");
width: 20px;
height: 20px;
background: black;
border-radius: 50%;
}
<div class="page">
<div class="container">
<svg>
<path d="M10 80 C 40 10, 65 10, 95 80 S 150 150, 180 80"/>
</svg>
<div class="ball"></div>
</div>
</div>
The drawbacks to this are that you'll have to recreate your specific path using SVG, which could take a bit of learning time if you aren't familiar with the syntax. The path is also not going to be responsive to screen width so you'd have to recalculate it a few times if that is important to you.
If that's not an option then you're basically going to have to write or find a script which is capable of generating a given sine wave, and then calculating coordinate position along it based on percentage. If it's not exact then it's never going to line up properly.
I'm trying to change the size (or scale) of a div while scrolling.
This div has a .8 scale attached to it css. I'd like to reach a scale of 1 progressively while scrolling.
IntersectionObserver seems to be a good choice to work with instead of scroll event but i don't know if i can change the state of an element using it.
You can change the scale of a div using.
document.getElementById("scaledDiv").style.transform = "scale(1)";
The scroll event should do what you want it to do. You can continue to add more if statements and check how many pixels they are scrolling to change it gradually to 1 or even back to 0.8 when they scroll back up. The 50 below represents 50 pixels from the top of the page.
window.onscroll = function() {
if (document.body.scrollTop > 50 || document.documentElement.scrollTop > 50) {
// They are scrolling past a certain position
document.getElementById("scaledDiv").style.transform = "scale(1)";
} else {
// They are scrolling back
}
};
I hope this will help you:
const container = document.querySelector('.container');
const containerHeight = container.scrollHeight;
const iWillExpand = document.querySelector('.iWillExpand');
container.onscroll = function(e) {
iWillExpand.style.transform = `scale(${0.8 + 0.2 * container.scrollTop / (containerHeight - 300)})`;
};
.container {
height: 300px;
width: 100%;
overflow-y: scroll;
}
.scrollMe {
height: 1500px;
width: 100%;
}
.iWillExpand {
position: fixed;
width: 200px;
height: 200px;
top: 10px;
left: 10px;
background-color: aqua;
transform: scale(0.8);
}
<div class='container'>
<div class='scrollMe' />
<div class='iWillExpand' />
</div>
So I sort of got it working. I believe I am not understanding the javascript correctly.
I took this from another thread, however it isn't behaving quite the way I am trying to achieve. I see the variables are a math equation that bases the movement on the window height.
How can I manipulate the equation so that I can control "Some cool text."'s initial position (if you notice on load it takes the correct position, and then on scroll it gets moved by JS) to stay where I want it?
What controls the speed and intensity of the movement and how can I manipulate that?
I believe I am just not understanding the syntax that controls all these variables, can you point me in the right direction for some reading to understand these specific variables? Thank you. :D
https://jsfiddle.net/codingcrafter/kv9od1ju/22/
/* Custom Horizontal Scrolling Parallax */
.hero-two {
overflow: hidden;
position: relative;
min-height: 500px;
}
h1 {
-webkit-text-stroke-width: 0.1rem;
-webkit-text-stroke-color: black;
color: #fff;
font-family: 'Open Sans', Helvetica, Times New Roman !important;
font-weight: 900;
}
.para-ele {
position: absolute;
width: 100%;
font-size: 5rem;
}
#hero-first {
left: 75%;
top: 15%;
}
#hero-second {
left: -32%;
bottom: 10%;
}
.container {
position: relative;
box-sizing: border-box;
width: 100%;
height: 100%;
}
<div class="container">
<div class="hero-two">
<h1 id="hero-first" class="h1 para-ele">
Some cool text.
</h1>
<h1 id="hero-second" class="h1 para-ele">
Some boring text.
</h1>
</div>
</div>
$(document).ready(function() {
var $horizontal = $('#hero-first');
$(window).scroll(function() {
var s = $(this).scrollTop(),
d = $(document).height(),
c = $(this).height();
scrollPercent = (s / (d - c));
var position = (scrollPercent * ($(document).width() - $horizontal.width()));
$horizontal.css({
'left': position
});
});
});
So you want to move the text from left to right or right to left?
I have done something similar to your issue but I used jQuery to handle the scroll effect.
If you are going to use the code below you will need to wrap the text within a element with the class Introduction
As the page scrolls the element will append the styles dynamically to the element.
<h1 class="introduction">
WE ARE A <br><span class="d">DIGITAL</span><br>PARTNER
</h1>
$(window).scroll(function() {
var wScroll = $(this).scrollTop();
$(".introduction").css({
transform: "translateX(-" + wScroll / 23 + "%)"
})
});
Demo: https://guide-nancy-64871.netlify.com/
When page is scrolled the header text moves to the left.
Read more on css transform: https://css-tricks.com/almanac/properties/t/transform/
Hope this helps!
What I'd like to do is animate a small image as well as a div (or an image within a div) from the right to the left of the screen, repeating once the image/div leaves the screen.
I found an example online that moves an image/div from left to right, but not all the way to the other side of the screen, and I am struggling to make it from right to left.
Here's what I have been doing
function moveTruck() {
$("#ImageToMove").animate({
"margin-right": "5000px"
}, 3000, function () { $("#ImageToMove").css("margin-right", "10000"); moveTruck(); });
}
moveTruck();
Playing with the margin-right values. My CSS class is:
.HomeImageAnimate{
position:absolute;
margin-top:80px;
right:1000px;
}
Try setting , animating left property using values of window.innerWidth , container element width
(function fx(el) {
$(el).css("left", window.innerWidth)
.animate({
left: "-" + (window.innerWidth - $(el).width() * 2)
}, 3000, "linear", function() {
fx(this)
})
}($("div")))
body {
overflow: hidden;
}
div {
width: 50px;
height: 50px;
position: absolute;
}
img {
background: gold;
width: 50px;
height: 50px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<div>
<img />
</div>
Try this out, this truck div repeatedly goes from right to left.
HTML:
<div class="truck"></div>
CSS:
body{
background: green;
overflow: hidden;
}
.truck {
margin-top:20px;
width: 272px;
height: 174px;
cursor:pointer;
position: absolute;
margin-right: -150px;
z-index: 3;
background: red;
border-radius:4px;
width:200px;
height:50px;
}
JS:
$(function() {
var moveTruck = function(){
$(".truck").delay(2000).animate( {'right': '120%' }, 5000,'linear',function(){
$(this).css({'right': '-50px'});
moveTruck();
});
}
moveTruck();
})
CODEPEN DEMO
function move(){
width = $(window).width();
objectWidth = $('#demo').width();
margin = width + objectWidth + 'px';
restart = -100 - objectWidth + 'px';
$('#demo').animate({
'margin-left': margin
}, 3000, function(){
$('#demo').css('margin-left', restart);
move();
});
}
move();
Try this out, it calculates the exact width of object and window - should always work no matter the screen size. You were trying to use an absolute pixel value, won't always work.
https://jsfiddle.net/w9pgmm9d/3/
My HTML basically looks like this:
<div id="#container">
<div id="left_col">
left stuff
</div>
<div id="middle_col">
middle stuff
</div>
<div id="right_col">
<div id="anchor"></div>
<div id="floater>
The problem div
</div>
</div>
</div>
The container div is pushed 82px to the left, because I don't want the rightmost column to be used as part of the centering (there is a header navigation bar above that is the size of left_col and middle_col):
#container {
width: 1124px;
margin-left: auto;
margin-right: auto;
text-align: left;
color: #656f79;
position: relative;
left: 82px;
}
#left_col {
float:left;
width: 410px;
background-color: #fff;
padding-bottom: 10px;
}
#middle_col {
width: 545px;
float: left;
}
#right_col {
float: left;
width: 154px;
margin-left: 5px;
position:relative;
}
#floater {
width: 154px;
}
I'm using the following javascript to keep the #floater div in position as you scroll down the page:
var a = function() {
var b = $(window).scrollTop();
var d = $("#anchor").offset().top;
var c = $("#floater");
if (b > d) {
c.css({position:"fixed",top:"10px"});
} else {
c.css({position:"absolute",top:""});
}
};
$(window).scroll(a);
a();
The problem I'm having is that in WebKit based browsers, once jQuery makes the floater div's positioning fixed so it will stay 10px from the top, that "left: 82px" from #container goes out the window, causing #floater to jump 82px to the left. This doesn't happen in FF or IE. Does anybody know a solution to this?
Update: Solved
I've solved this problem by not using fixed positioning, but instead using absolute positioning. I changed the javascript to set the top CSS property of div#floater to be based on the value $(window).scrollTop() if div#anchor's top offset is greater than $(window).scrollTop(). Pretty simple.
So the a() function now looks like this:
var a = function() {
var b = $(window).scrollTop();
var d = $("#anchor").offset().top;
var c = $("#floater");
if (b > d) {
var t = b-200; //200px is the height of the header, I subtract to make it float near the top
c.css({top:t+"px"});
} else {
c.css({top:""});
}
};