how to divide a background image in small blocks while using animejs - javascript

I'm trying to create a photo dispersion effect with the help of animejs.
Also, I've divided my background image in small blocks by keeping the background position fixed and till now its fine. like this:
But when I include anime js in it, my background doesn't seems to be a single one. Those all block takes same part of the image like this:
Here is the complete code:
let photoContainer = document.querySelector(".photoContainer")
for(let i = 0; i<100; i++){
let ele = document.createElement("div");
ele.classList.add("block");
photoContainer.appendChild(ele);
}
let block = document.querySelectorAll(".block")
let animation = anime.timeline({
targets: block,
easing: "easeInOutExpo",
loop: true,
delay: anime.stagger(20, {start:0}),
})
animation
.add({
delay: 4000,
scale: 0,
translateX: function(){return anime.random(-360,2100);},
translateY: function(){return anime.random(-360,2100);},
rotate: function(){return anime.random(360,-360);},
duration : function(){return anime.random(500,3000);}
})
.add({
scale: 1,
translateX:0,
translateY: 0,
rotate: 0,
duration : function(){return anime.random(2000,3000);}
})
.photoContainer{
position: relative;
display: flex;
flex-wrap: wrap;
transform-style: preserve-3d;
border: 2px solid red;
}
.photoContainer .block{
position: relative;
width: 5vh;
height: 5vh;
transform-style: preserve-3d;
perspective: 1000px;
box-sizing: border-box;
border: 2px solid green;
background-image: url(img.png);
background-color:red ;
background-size: 50vh 50vh;
background-attachment: fixed;
background-repeat: no-repeat;
background-position: top;
}
.dispersionContainer{
width: 50vh;
height: 50vh;
margin: 0px auto;
/* border-radius:50% ; */
background-color: black;
overflow: hidden;
border: 2px solid red;
}
<body>
<section id="spanContainer">
<div class="dispersionContainer">
<div class="photoContainer"></div>
</div>
</section>
</body>
Note: When I pushed this code to github previously, it was fine but when I cloned it again this problem arised.
Thanks in advance.

Related

How do I "perfectly" center an object following an SVG path in Anime.js?

I'm moving a 20px square around a circle path in SVG, using Anime.js. The square, however, is not perfectly centered in it's circular path:
anime({
targets: '.square',
translateX: path('x'),
translateY: path('y'),
rotate: path('angle'),
easing: 'linear',
duration: 10000,
loop: true,
});
https://codepen.io/gremo/pen/wvKjrMW
I've found similar examples, but I can't understand the math for making this work:
Here the object is centered using top/left/margin (even with negative values)
Here the object is centered using only top/left (with negative values)
This happens because your object (square) is indeed following the path. However, the object is translated based on the first pixel on the top left value (so if you make a 1px x 1px square, you should see that the square is following the path nicely). That is why the object's top left-hand corner is always sticking to the line. What you want is for the middle section of the object to stick to the line.
Using a statically and manually computed value (50% of the box's original width and height) is plausible (e.g. giving -10px to both top and left). However, you might not want to do this when there are many objects being animated (as you'll need to update all the CSS codes when change happens). Instead, we can use the pseudo-element ::after on your .square and translate it by 50% of its width to the left and 50% of its height to the top. This way, the object's point which will stick to the line is the center part of the square. Now, when you update the width and height of your original .square element, you need not update the top and left value. You can't simply add the transform: translate(-50%, -50%) value to the original .square div because it will be animated using Anime.js and the initial transform value will be lost. Getting the computed initial transform value from the JS is tricky.
document.addEventListener('DOMContentLoaded', function() {
const path = anime.path('.circle path');
anime({
targets: '.square',
translateX: path('x'),
translateY: path('y'),
easing: 'linear',
duration: 10000,
loop: true,
});
});
body {
background-color: #001f3f;
}
.container {
position: relative;
margin: 0 auto;
max-width: 500px;
}
.circle {
fill: none;
stroke: #b10dc9;
}
.square {
position: absolute;
top: 0;
left: 0;
display: inline-block;
width: 20px;
height: 20px;
}
.square::after {
content: '';
position: absolute;
width: 100%;
height: 100%;
transform: translate(-50%, -50%);
background-color: #f012be;
}
<script src="https://unpkg.com/animejs#3.2.0/lib/anime.min.js"></script>
<div class="container">
<svg class="circle" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
<path d="M400,250c0,82.84-67.16,150-150,150s-150-67.16-150-150s67.16-150,150-150S400,167.16,400,250z" />
</svg>
<span class="square"></span>
</div>
To understand the logic add another element with a different width/height to see the reference for each object:
document.addEventListener('DOMContentLoaded', function() {
const path = anime.path('.circle path');
anime({
targets: '.square',
translateX:path('x'),
translateY: path('y'),
easing: 'linear',
duration: 10000,
loop: true,
});
anime({
targets: '.square2',
translateX: path('x'),
translateY: path('y'),
easing: 'linear',
duration: 10000,
loop: true,
});
});
body {
background-color: #001f3f;
}
.container {
position: relative;
margin: 0 auto;
max-width: 500px;
}
.circle {
fill: none;
stroke: #b10dc9;
}
.square {
position: absolute;
top: 0;
left: 0;
display: inline-block;
width: 20px;
height: 20px;
background-color: #f012be;
}
.square2 {
position: absolute;
top: 0;
left: 0;
display: inline-block;
width: 40px;
height: 40px;
background-color: blue;
}
<script src="https://unpkg.com/animejs#3.2.0/lib/anime.min.js"></script>
<div class="container">
<svg class="circle" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
<path d="M400,250c0,82.84-67.16,150-150,150s-150-67.16-150-150s67.16-150,150-150S400,167.16,400,250z" />
</svg>
<span class="square2"></span>
<span class="square"></span>
</div>
As you can see, the top/left corner is following the path. To avoid this you can either use negative left/top to offset the element and have it centred or consdier a different CSS to make something generic.
I made the element with a 0 dimension and considered a box-shadw to create the square shape:
document.addEventListener('DOMContentLoaded', function() {
const path = anime.path('.circle path');
anime({
targets: '.square',
translateX:path('x'),
translateY: path('y'),
easing: 'linear',
duration: 10000,
loop: true,
});
anime({
targets: '.square2',
translateX: path('x'),
translateY: path('y'),
easing: 'linear',
duration: 10000,
loop: true,
});
});
body {
background-color: #001f3f;
}
.container {
position: relative;
margin: 0 auto;
max-width: 500px;
}
.circle {
fill: none;
stroke: #b10dc9;
}
.square {
content:"";
position: absolute;
left:0;
right:0;
width: 0;
height: 0;
box-shadow:0 0 0 10px #f012be;
}
.square2 {
position: absolute;
top: 0;
left: 0;
width: 0;
height: 0;
box-shadow:0 0 0 20px blue;
}
<script src="https://unpkg.com/animejs#3.2.0/lib/anime.min.js"></script>
<div class="container">
<svg class="circle" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 500">
<path d="M400,250c0,82.84-67.16,150-150,150s-150-67.16-150-150s67.16-150,150-150S400,167.16,400,250z" />
</svg>
<span class="square2"></span>
<span class="square"></span>
</div>

Change transition-duration with add/removeClass

I'm trying to make a simple pen with a button. When "on" is pressed the cover should slide and cover "on". When "off" is pressed the cover should cover "off". It works the way I have it, but when I try to add some transition effects nothing works. I tried adding transition-duration: 1s; to every class in the project but no luck.
Here's my codepen.
https://codepen.io/Alex-Iron/pen/eMORVV
My code is this:
HTML
<div id="switch" class="silver-background">
<div id="wrapper">
<div class="silver-background" id="cover">
<div id="cover-inner"></div>
</div>
<div id="on" class="on-left">on</div>
<div id="off">off</div>
</div>
</div>
SCSS
$radius: 7px;
$height: 100px;
$width: $height*1.5;
#switch{
width: $width*2.1;
height: $height*1.2;
display: grid;
position: relative;
}
.silver-background{
border-radius: $radius;
background: silver;
}
#wrapper{
margin: auto;
display: flex;
}
#on, #off, #cover, #cover-inner{
font-size: $height/3;
height: $height;
width: $width;
line-height: $height;
text-align: center;
text-transform: uppercase;
font-family: sans-serif;
}
#on{
background: radial-gradient(green, green, black);
border-radius: $radius 0 0 $radius;
color: lightgreen;
}
#off{
background: radial-gradient(#A00000, #A00000, black);
border-radius: 0 $radius $radius 0;
color: #EC6666*1.3;
}
#cover{
position: absolute;
border: 1px solid black;
width: $width*2.1/2;
height: $height*1.2;
display: grid;
top: 0;
}
#cover-inner{
width: $width*0.9;
background-color: white;
border-radius: $radius;
margin: auto;
}
.on-left{
left: 0;
}
.on-right{
right: 0;
}
My jQuery code.
$("#off").on('click',()=>{
$('#cover').removeClass('on-left');
$('#cover').addClass('on-right');
});
$('#on').on('click',()=>{
$('#cover').removeClass('on-right');
$('#cover').addClass('on-left');
})
I've updated your pen:
https://codepen.io/anon/pen/geOpgz
You should use the transition property of css:
#cover{
...
left: 0;
transition: 1s left;
}
The transition property can be used to animate a property value change. It is important, that your class only changes a property value f.e. left and not switches from left: 0 to right: 0:
#cover.on-left{
left: 0;
}
#cover.on-right{
left: $width;
}
In your case, the new value of your left property on right position is left: $width*2.1 / 2 cause your wrapper has the following width: width: $width*2.1.
By the way, i yould suggest you to use the toggleClass function of jquery:
$("#wrapper").on('click',()=>{
$('#cover').toggleClass('on-right');
});
Now you can click your wrapper on any position and it toggles the "on" and "off" with only one class .on-right and less javascript code:
https://codepen.io/anon/pen/QmWjwb
Your id="cover" should have on-left from start, and then give that #cover property transition: left 0.2s ease and class .on-right should have left: 150px since you cant transition from left: 0 to right: 0.
Here is the updated pen: https://codepen.io/zmuci/pen/JLjdEb

How do I stop an image at the bottom of the window?

$(".raindrop1").clone().removeClass("raindrop1").addClass("raindropDelete").appendTo("body").css({
left: $(".shape").position().left - 29.50,
top: $(".shape").position().top + 1,
position: "relative"
}).animate({
top: "+=1000"
}, function() {
$(".raindropDelete").remove();
});
body {
background: rgb(0, 0, 0);
}
.shape {
border-radius: 50px;
width: 10px;
height: 10px;
background-color: white;
position: absolute;
left: 50%;
top: 50%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="shape" onclick="curse()"></div>
<img src='http://images.clipartpanda.com/raindrop-clipart-RTGdn5bTL.png' width="15px" class="raindrop1">
I got this bit of code but I just can't seem to get it to work the way I want to. I want to make an image fall down to the bottom of the screen but to delete itself just before a scrollbar appears.
JS:
$(".raindrop1").clone().removeClass("raindrop1").addClass("raindropDelete").appendTo("body").css({
left: $(".shape").position().left - 29.50,
top: $(".shape").position().top + 1,
position: "relative"
}).animate({top :"+=1000"}, function() {
$(".raindropDelete").remove();
});
HTML:
<div class = "shape" onclick = "curse()"></div>
<img src = 'http://images.clipartpanda.com/raindrop-clipart-RTGdn5bTL.png' width = "15px" class = "raindrop1">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
and CSS:
body{
background: rgb(0, 0, 0);
}
.shape{
border-radius: 50px;
width: 10px;
height: 10px;
background-color: white;
position: absolute;
left: 50%;
top: 50%;
}
Am I doing anything wrong?
JSFiddle
You are trying to remove your droplet in the function that is used to do something when animation is completed. So droplet animation is still going until it will reach +1000px from the top.
To remove before it falls below the window it's possible to use step option for animate method. What it does is looking what happens during animation and you can remove the droplet if when it falls below the edge.
Step Function
The second version of .animate() provides a step option — a callback
function that is fired at each step of the animation. This function is
useful for enabling custom animation types or altering the animation
as it is occurring. It accepts two arguments (now and fx), and this is
set to the DOM element being animated.
now: the numeric value of the property being animated at each step
fx: a reference to the jQuery.fx prototype object, which contains a number
of properties such as elem for the animated element, start and end for
the first and last value of the animated property, respectively, and
prop for the property being animated.
So what I've done is created a step function that each step looks if droplet is reached the edge of the window. If condition is met - just remove the droplet
$(".raindrop1").clone()
.removeClass("raindrop1")
.addClass("raindropDelete")
.appendTo("body").css({
left: $(".shape").position().left - 29.50,
top: $(".shape").position().top + 1,
position: "relative"
})
.animate({top :"+=100"},
{step: function(now) {
if (now+50 >= $(window).height())
$(".raindropDelete").remove();
}
},
function() {});
body{
background: rgb(0, 0, 0);
}
.shape{
border-radius: 50px;
width: 10px;
height: 10px;
background-color: white;
position: absolute;
left: 50%;
top: 50%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class = "shape" onclick = "curse()"></div>
<img src = 'http://images.clipartpanda.com/raindrop-clipart-RTGdn5bTL.png' width = "15px" class = "raindrop1">
using this css you can stick your image to the bottom of the window in all new browsers
.fix{
position:fixed;
bottom:0px;
left:50%;
}
<img src="yourimagepath" class="fix"/>
and for IE6 you can use
position:absolute; instead of fixed. It will position the image on the bottom of the page but as you scroll up the image will scroll with the page. Unfortunately position:fixed in not supported in IE6
Using this code you can detect if the user has reached to the bottom of the page. Here you can add your code for deleting the image. If you put the code here the image will be deleted automatic if the user reaches to the bottom of the page.
window.onscroll = function(ev) {
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
// you're at the bottom of the page
}
};
You can use sticky elements. They are elements on a page that will not be scrolled out of view. In other words it sticks to a visible area (viewport or scrolling box). You can create this with CSS using position: sticky;.
[Ref: http://www.hongkiat.com/blog/useful-css-tricks-you-might-have-overlooked/]
Look at the following code for an example:
https://codepen.io/rpsthecoder/pen/zGYXEX
HTML:
<h4>Scroll to see the sticky element <em>sticking</em></h4>
<div class="extra"></div>
<br />
<div id="wrapper">
<div id="sticky">
sticky
</div>
</div>
<br />
<div class="extra"></div>
CSS:
#sticky {
position: sticky;
background: #F762BC;
width: 100px;
height: 100px;
top: 70px;
left: 10px;
display: flex;
justify-content:center;
align-items:center;
box-shadow: 0 0 6px #000;
text-shadow: 0 0 4px #fff
}
#wrapper {
width: 75%;
margin: auto;
height: 400px;
background-color: #ccc;
}
.extra{
background: #ccc;
width: 75%;
margin: auto;
height: 100px;
}
body {
height: 1000px;
font-family: georgia;
}
h4{
text-align: center;
}

Animating two divs to loop right to left indefinitely

Here's my code:
HTML
<div class="screen screen1"></div>
<div class="screen screen2"></div>
CSS
.screen{
width: 100%;
height: 50%;
position: absolute;
background-color:#001;
background-image: radial-gradient(white 15%, transparent 16%),
radial-gradient(white 15%, transparent 16%);
background-size:60px 60px;
background-position: 0 0, 30px 30px;
}
.screen2{
left: 100%;
}
JavaScript
$(document).ready(function(){
screen1 = $('.screen1');
screen2 = $('.screen2');
move(screen1, screen2);
});
function move(first, second){
first.animate({left: '-100%'}, 3000, function(){
first.css('left', '100%');
move(second, first);
});
second.animate({left: 0}, 3000);
}
I want to animate two divs to make an infinite background repeating animation using jQuery. I came this far, and it works good for the most part except for the small pause that happens when I send .screen1 to the right.
Here's the fiddle:
https://jsfiddle.net/mavisme/a1275tuv/
How do I fix it to run smoothly?
You should totally drop that and try jQuery CSS animations:
#keyframes animate {
from {
background-position: 0 0;
}
to {
background-position: -60px 0;
}
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: sans-serif;
}
html, body {
height: 100%;
min-height: 100%;
overflow: hidden;
}
.screen {
width: 100%;
height: 100%;
position: absolute;
background-color: #001;
background-image: radial-gradient(white 15%, transparent 16%), radial-gradient(white 15%, transparent 16%);
background-size: 60px 60px;
animation: animate 300ms linear infinite;
}
<div class="screen"></div>
I assume you are unsatisfied with the "speeding up" and "slowing down" at the beginning and end of each cycle. Have a look at 'easing':
function move(first, second) {
first.animate({
left: '-100%',
}, 3000, 'linear', function() {
first.css('left', '100%');
move(second, first);
});
second.animate({
left: 0
}, 3000, 'linear');
}
easing (default: swing)
A string indicating which easing function to use for the transition.
http://api.jquery.com/animate/
Animating two divs to loop right to left indefinitely
Here's my code:
https://jsfiddle.net/a1275tuv/5/
$(function(){
var x = 0;
setInterval(function(){
x-=1;
$('.screen').css('background-position', x + 'px 0');
}, 10);
})

TweenLite animation suddenly changing elements' position?

First of all, you can find a simplified demo of my code in this JSFiddle and also below the question. I found that my problem happens the way I describe it in Google Chrome, so if you plan to try and fix the bug, please use that browser. I apologize if the code is not very well simplified; please consider that this is a snippet from a bigger project.
I'm working on a webapp that uses JQuery and GreenSock's TweenLite for animations.
This app consists on some menus that control everything, that are transitioned between using the bodyChange() function. This function has two parameters:
nextOrPrev, that runs one animation or another based on the value
provided ("next" or "prev"). Only the "next" animation is done yet, but that is not important for now. The "prev" animation, not yet used, just emits an alert("prev").
bodyFunction. The function provided will fill the body with the elements necessary for that menu, and the wrap them in a #bodyWrap.
In the demo I provide you with there are only two menus: The first one, mainMenu, with only a #playButton. When you click it, the bodyChange() function is called with the following parameters: ("next", playSettingsBody), playSettings being the second menu.
This is the problem: when you click the playButton, the button goes up a on the screen and then executes the TweenLite animation. I can't see, however, why does the button "jump up", instead of staying in the same place and execute the animation. This is probably due to a small mistake. What is it?
Thanks for any help.
mainMenuBody();
function mainMenuBody() {
$("body").append(
//BUTTONS
"<div id='playButton' class='mainButton'><div class='buttonText mainButtonText text'>PLAY</div></div>"
);
//WRAP
$("body").wrapInner("<div id='bodyWrap'></div>");
//BINDS
$("#playButton").bind("click", function() {
bodyChange("next", playSettingsBody);
});
}
function bodyChange(nextOrPrev, bodyFunction) {
switch (nextOrPrev) {
case "next":
//ANIMATION AND BODY CHANGE
TweenLite.to($("#bodyWrap"), .4, {
ease: Power2.easeIn,
transform: "rotateY(90deg)",
onComplete: function(){
$("body").empty();
//NEW STUFF
bodyFunction();
TweenLite.from($("#bodyWrap"), .4, {
ease: Power2.easeOut,
transform: "rotateY(90deg)"
});
}
});
//END OF ANIMATION AND BODY CHANGE
break;
case "prev":
alert("prev");
}
}
function playSettingsBody() {
$("body").append(
"<p class='text' id='CYTText'>This is the second menu!</p>"
);
}
body{
background-image: url("../resources/pics/Vignette2.png");
background-repeat: no-repeat;
background-position: center center;
background-attachment: fixed;
background-color: #02BFC1;
overflow:hidden;
margin: 0;
}
.text {
color: #FFFFFF;
font-family:Bebas Neue;
-webkit-user-select: none;
cursor: default;
text-shadow: 3px 3px 2px rgba(0,0,0,0.2);
}
.mainButton {
-webkit-transform:scale(1);
width: 200px;
height: 200px;
border: 10px solid #F1F2F0;
text-align:center;
background-color: #F37C2B;
/*background:#5F4A21;*/
display: table;
position: absolute;
margin: auto;
top: 150px;
bottom: 0;
-webkit-transition: all 0.5s ease;
cursor: pointer;
box-shadow: 0px 0px 30px rgba(0,0,0,0.4);
}
.mainButtonText {
position: relative;
display:table-cell;
vertical-align:middle;
-webkit-transform:scale(1);
font-size: 90px;
text-shadow: 4px 4px 2px rgba(0,0,0,0.2);
-webkit-transition: all 0.5s ease;
}
<script src="https://code.jquery.com/jquery-3.1.0.min.js" integrity="sha256-cCueBR6CsyA4/9szpPfrX3s49M9vUU5BgtiJj06wt/s=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.0/TweenMax.min.js"></script>
This problem is caused in your .mainButton class. Your code looks a little like this.
.mainButton {
position: absolute;
top: 150px;
bottom: 0;
//rest
}
By removing the line bottom: 0; your JSFiddle now works as expected. However, if you remove the line top: 150px; instead and leave in the bottom: 0 the problem still occurs. Unfortunately, I cannot provide an explanation for this. It might be worth posting a question on the GSAP forums inquiring about why this occurs works when positioning using bottom but not when using top
Edit
Since you need bottom: 0 and I wasn't able to fix your code I wrote an example which works using Timeline, a GSAP plugin. You can see this JSFiddle or the code example below.
var tl = new TimelineMax();
tl.pause();
tl.fromTo($("#click"), 1, {rotationY: 0, ease: Power2.easeOut}, {rotationY: 90, transformOrigin:"right", ease: Power2.easeOut})
.set($("#click2"), {css:{display: "table"}}, "-=0.6")
.fromTo($("#click2"), 1, {rotationY: -90, ease: Power2.easeOut}, {rotationY: 0, transformOrigin:"left", ease: Power2.easeOut}, "-=0.6");
$("#click").click(function() {
tl.play();
});
$("#click2").click(function() {
tl.reverse();
});
* {
margin: 0;
padding: 0;
}
body {
background-image: url("../resources/pics/Vignette2.png");
background-repeat: no-repeat;
background-position: center center;
background-attachment: fixed;
background-color: #02BFC1;
overflow: hidden;
}
div.one, div.two {
position: absolute;
bottom: 0;
height: 200px;
width: 200px;
background: #F37C2B;
text-align: center;
display: table;
cursor: pointer;
border: 10px solid #F1F2F0;
}
div.one .text, div.two .text {
position: relative;
display: table-cell;
vertical-align: middle;
color: #FFFFFF;
font-family: Bebas Neue;
font-size: 90px;
}
div.two {
display: none;
border-color: transparent;
background: none;
}
div.two .text {
font-size: 40px;
}
<script src="https://code.jquery.com/jquery-3.1.0.min.js" integrity="sha256-cCueBR6CsyA4/9szpPfrX3s49M9vUU5BgtiJj06wt/s=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.0/TweenMax.min.js"></script>
<div id="click" class="one">
<div class="text">
Play
</div>
</div>
<div id="click2" class="two">
<div class="text">
Second Menu
</div>
</div>

Categories

Resources