I've recently started working with Anime.js to animate my designs and I´ve been stuck in this for a while now, bet for many this is very simple!
I have a button that enlarges my div and would like to have the div in its initial state if the icon is clicked again.
My HTML:
var boxGetsLarger = anime({
targets: '.agent-button',
width: {
value: '+=300',
duration: 200,
easing: 'linear'
},
borderRadius: {
value: 83
},
duration: 200,
height: {
value: '+=20'
},
easing: 'linear',
autoplay: false
});
document.querySelector('.agent-button').onclick = boxGetsLarger.play;
.agent-button {
display: flex;
justify-content: space-between;
border-radius: 100px;
background: #ffffff;
box-shadow: 0pt 2pt 10pt #0000001f;
height: 91px;
width: 91px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/2.2.0/anime.min.js"></script>
<div class="agent-button close">
<img src="img/audio-bars.svg">
</div>
It is shame there is no built-in toggle function but there is a reverse function what this does is toggle the internal attribute reversed which, in turn, controls what the play function does.
In theory, you can just call reverse after play like so
var boxGetsLarger = anime({
targets: '.agent-button',
width: {
value: '+=300',
duration: 200,
easing: 'linear'
},
borderRadius: {
value: 83
},
duration: 200,
height: {
value: '+=20'
},
easing: 'linear',
autoplay: false
});
document.querySelector('.agent-button').onclick = function() {
boxGetsLarger.play();
boxGetsLarger.reverse();
}
.agent-button {
display: flex;
justify-content: space-between;
border-radius: 100px;
background: #ffffff;
box-shadow: 0pt 2pt 10pt #0000001f;
height: 91px;
width: 91px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/2.2.0/anime.min.js"></script>
<div class="agent-button close">
<img src="img/audio-bars.svg">
</div>
Only I found reverse was running before play was finished leading to some strange behaviour, I'd recommend taking advantage of the 'finished' promise built-in like so
var boxGetsLarger = anime({
targets: '.agent-button',
width: {
value: '+=300',
duration: 200,
easing: 'linear'
},
borderRadius: {
value: 83
},
duration: 200,
height: {
value: '+=20'
},
easing: 'linear',
autoplay: false
});
document.querySelector('.agent-button').onclick = function() {
boxGetsLarger.play();
boxGetsLarger.finished.then(() => {
boxGetsLarger.reverse();
})
}
.agent-button {
display: flex;
justify-content: space-between;
border-radius: 100px;
background: #ffffff;
box-shadow: 0pt 2pt 10pt #0000001f;
height: 91px;
width: 91px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/2.2.0/anime.min.js"></script>
<div class="agent-button close">
<img src="img/audio-bars.svg">
</div>
This will now only reverse the direction when play is finished.
I hope you find this helpful.
I use this to toggle anime.js animations on a single button.
To initiate reverse() the animation must have run once. You can check this by evaluating the property: 'began'. The first time your animation runs this property will be set 'true'.
console.log(boxGetsLarger); // began: false
document.querySelector('.agent-button').onclick = function() {
boxGetsLarger.play();
if (boxGetsLarger.began) {
boxGetsLarger.reverse();
}
console.log(boxGetsLarger); // began: true
}
What fixed it for me was juliangarnier/anime#577 (comment):
I encountered this issue today, here is my solution as a pen.
I think the confusion arises from when animations are paused, and how the reverse() method works:
Non-looped animations are automatically paused when they reach the end (or beginning when reversed).
The reverse() method only changes the playback direction, and doesn't unpause a paused animation.
Doing reverse() on an animation while it is in progress means it will continue to play in the opposite direction, but if the animation is at the beginning/end (i.e. paused), you will also need to do play() to get it started again.
From his linked CodePen:
function toggle() {
if (anim.began) {
anim.reverse()
if (anim.progress === 100 && anim.direction === 'reverse') {
anim.completed = false
}
}
if (anim.paused) {
anim.play()
}
}
Give this a try: (from docs)
boxGetsLarger.reverse();
I used this to toggle back and forth between an "open" state and a "closed" state.
const toggle = (animation, open) => {
if (open) {
animation.play();
if (animation.reversed) {
animation.reverse();
}
} else {
animation.play();
if (!animation.reversed) {
animation.reverse();
}
}
}
Related
I'm making an animation atm and wanted to animate a text once when I scroll there. Here is the code. The code works all fine I don't know why it won't work here. But I saw that the text fires every time I scroll there. How can I prevent this? So it only fires once?
var fadeUpNormal = anime.timeline({
loop: false,
autoplay: false,
}).add({
targets: '.fade-up-normal',
translateY: [100,0],
opacity: [0,1],
translateZ: 0,
easing: 'easeOutExpo',
duration: 1400,
delay: 1000;
});
$('.scroll-trigger').on('inview', function(event, isInView) {
if (isInView) {
fadeUpNormal.play();
} else {}
});
div {
background-color: #444;
height: 1000px;
display: flex;
justify-content: center;
align-items: center;
}
#wwrp1 {
color: black;
font-size: 3rem;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/protonet-jquery.inview/1.1.2/jquery.inview.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.1/anime.min.js"></script>
<div>
<div>
<p class="fade-up-normal scroll-trigger" id="wwrp1">This is an example</p>
</div>
</div>
The solution is just to use .one('inview') for .on('inview'). That was my bad!
I'm trying to find the most concise way to throttle a hover function with jQuery. There are many examples of this but they all seem to not work as intended. For example the use of $.throttle doesn't error but it stops the animation from working altogether. This is the code which I'm trying to throttle:
jQuery(document).ready(function($){
var $navTab = $('.nav-tab-parent');
function moveNavTab(e) {
TweenLite.to($navTab, 0.3, {
css: {
left: e.pageX,
top: e.pageY
}
});
}
$(window).on('mousemove', moveNavTab);
$(".toggle-bars").hover( // this is the .hover() function I need to throttle.
function() {
$(".nav-tab-parent").animate({
opacity: 1
});
$(".nav-tab-parent").delay(10).animate({
width: "36px",
easing: "swing"
});
$(".nav-tab").html("MENU");
$(".nav-tab").delay(350).animate({
opacity: 1
});
}, function() {
$(".nav-tab").animate({
opacity: 0
});
$(".nav-tab-parent").delay(150).animate({
width: "0",
opacity: 0,
easing: "swing"
});
}
);
});
I must be missing something here but can't figure it out. Any help in achieving this would be greatly appreciated!
Changed to use entirely GSAP and relying on .timescale() see the documentation — didn't know the underlying structure so will need some configuring but the basis is there. GSAP has a crazy deep documentation but should be familiar enough to jquery with object animations.
var tl = gsap.timeline().timeScale(-1);
tl.fromTo(".nav-tab-parent", {
autoAlpha: 0,
duration: 1
}, {
autoAlpha: 1,
duration: 1
});
$(".toggle-bars").hover(function() {
tl.timeScale(1);
}, function() {
tl.timeScale(-1);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.8.0/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="toggle-bars">.toggle-bars
<div class="nav-tab-parent">.nav-tab-parent</div>
</div>
I suppose you are trying to achieve something like this. You could try to use .stop() method - it will stop current animation and after that you can run next one. Try to play with arguments to choose what best will suit your case.
let $hover = $('.hover-box'),
$target = $('.animated-box');
function show() {
$target.stop(true, true).animate({
opacity: 1,
})
}
function hide() {
$target.stop(true, true).animate({
opacity: 0
})
}
$hover.hover(show, hide)
.hover-box,
.animated-box {
width: 100px;
height: 100px;
border-radius: 8px;
}
.hover-box {
border: 1px solid #ddd;
display: inline-flex;
align-items: center;
justify-content: center;
text-transform: uppercase;
font-family: sans-serif;
cursor: pointer;
margin-bottom: 16px;
}
.hover-box:hover {
background: #ddd;
}
.animated-box {
opacity: 0;
background: gold;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class='hover-box'>Hover</div>
<div class='animated-box'></div>
I am trying to create an animation with the width of an element, but even this basic code doesn't work and I can't figure out why, maybe someone can.
<script src="anime.min.js"></script>
<script src="jquery-3.1.0.js"></script>
<div id="centered">
</div>
<style>
#centered {
width: 500px;
height: 40vh;
background-color: blueviolet;
}
</style>
<script>
let t = anime.timeline({
target: '#centered',
loop: false,
autoplay: false,
width: 0,
duration: 1000,
});
t.play();
</script>
How about the following solutions?
Example 1 (With timeline)
var t = anime.timeline({
duration: 1000,
loop: false,
autoplay: false,
});
t.add({
targets: '#centered',
width: 0
})
t.play();
Example 2 (Without timeline)
var t = anime({
duration: 1000,
loop: false,
autoplay: false,
targets: '#centered',
width: 0
});
t.play();
For more information, it's better to check an official document.
https://animejs.com/documentation/
Your 'target' should be targets (plural). Following documentation, you should be adding (what I would call) keyframes via .add according to the timeline basics. Not certain if you need it explicitly.
let t = anime.timeline({
targets: '#centered',
loop: false,
autoplay: false
});
t.add({ width: 0, duration: 1000 });
t.play();
#centered {
width: 27px;
height: 40vh;
background-color: blueviolet;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/animejs/3.2.0/anime.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div id="centered">
</div>
I want to create a popout menu that is flush with the edge of the screen. It seems like popper doesn't like this because it always forces a margin of 5px. I've tried setting offset and padding values to 0, but it doesn't seem to work. Is there a way to do this without forcing it like
margin-left: -5px !important
Here are the tippy options ive included and a JSFiddle:
https://jsfiddle.net/tbgwknpf/1/
<div class="button">
click me!
<div id="menu-content">
this is a tippy!
</div>
</div>
</div>
body {
margin: 0;
}
.bar {
height: 100px;
width: 100%;
background: coral;
}
.button {
background: aquamarine;
height: 100%;
width: 200px;
display: flex;
align-items: center;
justify-content: center;
}
const menu = document.getElementById("menu-content");
menu.style.display = 'block';
tippy('.button',
{
content: menu,
allowHTML: true,
interactive: true,
trigger: 'click',
hideOnClick: 'toggle',
placement: 'bottom-start',
offset: [0, 0],
popperOptions: {
modifiers: [
{
name: 'offset',
options: {
offset: [0, 0]
}
},
{
name: 'flip',
options: {
padding: 0,
flipVariations: false
}
}
]
},
});
If I add a margin to the button element, the tippy will align flush against the edge like I want it to. It is only when I ask it to be flush against the screen that it adds the translationX of 5px
You can do it using a theme.
JS:
tippy(targets, {
theme: "your-theme",
});
CSS:
.tippy-box[data-theme~="your-theme"] .tippy-content {
padding: 0;
}
Note the extra .tippy-content as the padding is in the child of .tippy-box.
You don't have to change any CSS styles. You just need to pass the right options to the underlying Popper.js:
popperOptions: {
modifiers: [
{
name: 'preventOverflow',
options: {
padding: 0,
},
},
],
},
I am trying to alternate display between two containers on a page using fadeOut/fadeIn & slideUp/slideDown. I would like the transition from the first container to the second to look the same as the transition from the second to the first; they fade in/out respectively, the current container slides up and away, and the other slides up from below it, all simultaneously. The first button triggers the animation described, but when I use the second button to transition to the first element the first element suddenly pops into existence while fading in jerking the page down, the second fades out, but no slide occurs. Thanks for your help, and let me know if I can clarify for you!
var main = function () {
$('.button-1').click(function () {
$('.container-1').fadeOut({ duration: 1400, queue: false }).slideUp(1400);
$('.container-2').fadeIn({ duration: 1400, queue: false }).slideDown(1400);
});
$('.button-2').click(function () {
$('.container-2').stop(true, true).fadeOut({ duration: 1400, queue: true }).slideUp(1400);
$('.container-1').fadeIn({ duration: 1400, queue: false }).slideDown(1400);
});
$(document).ready(main);
you actually only need 1 button to do this if you animate the height and opacity with toggle. ive added it twice since your use case was for 2 buttons
js fiddle here
js
var main = function () {
$('.button-1').click(function () {
$('.container-1')
.stop(true, true)
.animate({
height: "toggle",
opacity: "toggle"
}, 1400);
$('.container-2')
.stop(true, true)
.animate({
height: "toggle",
opacity: "toggle"
}, 1400);
});
$('.button-2').click(function () {
$('.container-2')
.stop(true, true)
.animate({
height: "toggle",
opacity: "toggle"
}, 1400);
$('.container-1')
.stop(true, true)
.animate({
height: "toggle",
opacity: "toggle"
}, 1400);
});
}
$(document).ready(main);
html
<div class=container-1>container1</div>
<div class=container-2>container2</div>
<input type=button class=button-1 value=button1>
<input type=button class=button-2 value=button2>
css
.button-1 {
color: red;
}
.button-2 {
color: blue;
}
.container-1, .container-2 {
width: 100px;
height: 100px;
}
.container-1 {
background-color: green;
}
.container-2 {
display: none;
background-color: orange;
}
Not sure if this is what you want. But here is one way to switch between two containers with slide and fade at the same time:
HTML:
<input type="button" class="redclick" value="Red"></input>
<input type="button" class="blueclick" value="Blue"></input>
<div class="red"></div>
<div class="blue"></div>
CSS:
.red, .blue{
width:200px;
height:200px;
position: absolute;
}
.red{ background:red; }
.blue{ background:blue; }
Javascript:
$(function() {
$('.red').hide();
$('.blue').show();
$(".blueclick").click(function() {
if($('.red').css('opacity') == '1'){
$('.red').fadeOut({ duration: 1400, queue: false }).slideUp(1400);
$('.blue').slideDown({ duration: 1400, queue: false }).fadeIn(1400);
}
});
$(".redclick").click(function() {
if($('.blue').css('opacity') == '1'){
$('.blue').fadeOut({ duration: 1400, queue: false }).slideUp(1400);
$('.red').slideDown({ duration: 1400, queue: false }).fadeIn(1400);
}
});
});
JSFiddle Demo
Hope this helps.