I have the following: http://jsfiddle.net/JfGVE/318/
The issue is that it's not a smooth animation. How I wanted it to work was:
Center the icon to the middle of the screen before displaying it.
Fade it in, and while it's fading in, resize it to something slightly larger, while staying in the dead center of the screen.
Fade it out.
How can I fix the animation to be completely smooth and feel as if it's a "pulse".
HTML:
Click Me!
<i class="fa fa-heart"></i>
CSS:
.fa-heart {
font-size: 48px;
color: red;
position: absolute;
display: none;
}
jQuery:
$(document).on("click", "a", function() {
var center_width = $(window).width() / 2;
var center_height = $(window).height() / 2;
/* Set the icon to the center of the screen. */
$('.fa-heart').css({ 'left': center_width, 'top': center_height });
/* Fade the icon in, resize it, and fade it out. */
$('.fa-heart').fadeIn();
$('.fa-heart').animate({ fontSize: '60px' }, 300);
$('.fa-heart').fadeOut();
});
Check this out: http://jsfiddle.net/JfGVE/336/
$(document).on("click", "a", function() {
var center_width = $(window).width() / 2;
var center_height = $(window).height() / 2;
/* Set the icon to the center of the screen. */
$('.fa-heart').css({ 'left' : center_width - 24, 'top': center_height - 24 });
/* Fade the icon in, resize it, and fade it out. */
$('.fa-heart').animate({ fontSize: '60px', opacity: 1, 'left' : center_width - 30, 'top': center_height - 30}, 250);
$('.fa-heart').animate({ fontSize: '48px', opacity: 0, 'left' : center_width - 24, 'top': center_height - 24}, 250);
});
What I did is instead of using the fadeIn() and fadeOut() I used the animate() to change the size and opacity at the same time. You can change the times so they resemble a real heart beat but because both the size change and opacity change are in the same animate() they will happen at the same time. The third value in the animate() is to set the center of the picture to the center of the page. This needs to be center_height (or center_width) - 1/2 of the picture height so the center of the image is aligned with the center of the screen. You need the offset because in normal CSS the position tag aligns your picture with the specified value relative to the top left corner (0, 0 of the picture). The times of the animate can be changed depending on how fast / slow you want the heart to "beat".
You can animate CSS properties instead of using fadeIn() and fadeOut(). And for centering the heart you need to:
(width/height) of the window (width/height) of the heart
---------------------------- - ---------------------------
2 2
Demo on Fiddle
jQuery:
$(document).on("click", "a", function() {
var w = ($(window).width() / 2) - ($('i').width() / 2);
var h = ($(window).height() / 2) - ($('i').width() / 2);
$('.fa-heart').css({ 'left': w, 'top': h });
$('.fa-heart').animate({ fontSize: '48px', opacity: '0'}, 100);
$('.fa-heart').animate({ fontSize: '60px', opacity: '1'}, 700);
$('.fa-heart').animate({ fontSize: '48px', opacity: '0'}, 500);
});
CSS:
.fa-heart {
font-size: 48px;
color: red;
position: absolute;
opacity: 0;
}
You could achieve a smooth and (arguable) faster animation using Julian Shapiro's velocity.js plugin
just tweak your css giving opacity: 0 instead of display: none to your element
.fa-heart {
font-size: 48px;
color: red;
position: absolute;
/* display: none; */
opacity: 0;
}
then velocity's loop option will give you the effect you want
jQuery(document).ready(function ($) {
$("body").on("click", ".click", function () {
var center_width = $(window).width() / 2;
var center_height = $(window).height() / 2;
$('.fa-heart').css({
left: center_width,
top: center_height
}).velocity({
opacity: 1,
fontSize: "60px"
}, {
loop: true, // animate from initial values back and forth
duration: 400 // adjust as needed
});
});
});
... that way you don't need fadeIn or fadeOut, or animate back to the original values or chain several animate() methods
See JSFIDDLE
Notice that you can set how many times you want the animation to take place by setting the number in the loop option like
loop: 1 // or twice, three times, etc (true does infinite loop)
http://jsfiddle.net/nao9k1Lx/1/
Also notice I gave a class click to the <a> tag to be more specific.
I've updated your JsFiddle, tell me if this is what you needed, i can explain the differences.
html
Click Me!
<div class="anim-container">
<i class="fa fa-heart"></i>
</div>
javascript
$(document).on("click", "a", function() {
var center_width = $(window).width() / 2;
var center_height = $(window).height() / 2;
/* Set the icon to the center of the screen. */
/* Fade the icon in, resize it, and fade it out. */
$('.fa-heart').fadeIn();
$('.fa-heart').animate({ fontSize: '55px' }, {duration: 300, queue: false});
$('.fa-heart').animate({ fontSize: '48px' }, 300);
$('.fa-heart').fadeOut();
});
Related
How can I animate an element with Javascript vanilla?
Similar with jquery. Example:
$( "button.continue" ).animate({left: "100px", top: "200px"}, 5000);
Where we pass the attribute, the desired value and the time.
In my case I need the left and top position to animate and slide.
Solution
I've done as #IceMetalPunk sugested and added the animation by css only when I need to animate.
document.getElementById("animate").addEventListener("click", function(){
let e = document.getElementById('elementToAnimate');
e.classList.add("animate");
setTimeout(()=> e.classList.remove("animate"), 500);
e.style.top = Math.floor(Math.random() * window.innerHeight) + 'px';
e.style.left = Math.floor(Math.random() * window.innerWidth) + 'px';
});
document.getElementById("dontAnimate").addEventListener("click", function(){
let e = document.getElementById('elementToAnimate');
e.style.top = Math.floor(Math.random() * window.innerHeight) + 'px';
e.style.left = Math.floor(Math.random() * window.innerWidth) + 'px';
});
#elementToAnimate {
width: 20px;
height: 20px;
background: red;
position: absolute;
top: 0;
left: 0;
}
#elementToAnimate.animate {
transition: left 500ms ease-in-out, top 500ms ease-in-out;
}
<div id="elementToAnimate"></div>
<button id="animate">Animate</button>
<button id="dontAnimate">Dont Animate</button>
Try using CSS transitions. In CSS, do something like this:
button.continue {
transition: 5s;
}
Then in JS, you can just set the left/top values:
document.querySelectorAll('button.continue').forEach(button => {
button.style.left = '100px';
button.style.top = '200px';
});
Tested in Firefox.
document
.querySelector(".text.thank-you")
.animate({ opacity: [0, 1] }, { duration: 5000, iterations: 1, easing: "ease-out" })
.onfinish = (e) => {
e.target.effect.target.style.opacity = 1;
};
Take a look at the Web Animation API. Its an experimental feature so Browser Support (mainly Safari) might be an issue for you. Otherwise you can do it the way others have already pointed out.
Try using WebComponents, you can perform any kind of animation using only VanillaJS, there are predefined animations like Animate.css but you can create custom animations by using keyFrames:
<!-- Add Web Animations Polyfill :) -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/web-animations/2.3.2/web-animations.min.js"></script>
<script type="module" src="https://unpkg.com/#proyecto26/animatable-component#1.0.0/dist/animatable-component/animatable-component.esm.js"></script>
<script nomodule="" src="https://unpkg.com/#proyecto26/animatable-component#1.0.0/dist/animatable-component/animatable-component.js"></script>
<animatable-component
autoplay
easing="ease-in-out"
duration="1200"
delay="300"
animation="heartBeat"
iterations="Infinity"
style="display: flex;align-self: center;"
>
<h1>Hello World</h1>
</animatable-component>
For more details check here: https://github.com/proyecto26/animatable-component
I recently just started getting into html and was wondering how can I implement the following code and be more efficient and use an arrayList.
<!--
This was me just trying to play around with arrays and elements
var elements = document.getElementsByClassName("[id^=pop]");
var arr = jQuery.makeArray(elements);
-->
var p = $("[id^=pop]");
var position = p.position();
$("[id^=pop]").hover(function() {
$(this).css("cursor", "pointer");
$(this).animate({
width: "400px",
height: "400px",
top: position.top*.7,
left: position.left*.7
}, 150);
}, function() {
$(this).animate({
width: "300px",
height: "300px",
top: position.top,
left: position.left
}, 150);
});
As of now, when an image id equals pop0, and then another one equal pop1. They both will animate to the first image's height and width. How can I use an array so every img has its own position and won't be based off the first image that is loaded but rather their own top and left coordinates?
As mentioned in the comments, you need to move your position variable from outside of your hover event handlers to inside your hover event handlers. This will set the context to the currently hovered item.
Currently your p variable stores an array of all elements beginning with an ID that starts with pop. Then you are storing a reference to the first element's position and never updating by setting the value of position outside of your hover event handlers.
Here's an example with a small bit of caching so you're not always querying the DOM.
var $pop = $( '[id^=pop]' );
$pop.hover( function hoverIn() {
var $this = $( this ),
pos = $this.position();
$this
.css( 'cursor', 'pointer' ) // <= Possibly do this via CSS.
.animate( {
width: '400px',
height: '400px',
top: pos.top * 0.7,
left: pos.left * 0.7
}, 150 );
}, function hoverOut() {
var $this = $( this ),
pos = $this.position();
$this.animate( {
width: '300px',
height: '300px',
top: pos.top,
left: pos.left
}, 150 );
} );
I want to set multiple animation on single element on the phone, when trigger them one by one. I achieve this by the under method , but have 2 problems:
I need accurate position and size, so I use top bottom width height. But I know use these properties, the browser need to render again, so it is not efficient.
On the second animation, although I set animation-fill-mode: forwards, but still need to set 0% keyframes to assure second animation start point is on the first animation end point.
Thanks for more efficient method.
my demo
html:
<button id="first">first</button>
<button id="second">second</button>
<div class="moon"></div>
css:
.first {
animation-name: first;
}
.second {
animation-name: second;
}
#-webkit-keyframes first {
100% {
height: 2.5rem;
width: 2.5rem;
left: 4.1rem;
bottom: 11.7rem;
}
}
#-webkit-keyframes second {
0% {
height: 2.5rem;
width: 2.5rem;
left: 4.1rem;
bottom: 11.7rem;
}
100% {
height: 4rem;
width: 4rem;
left: 5.8rem;
bottom: 10.5rem;
}
}
js:
var $moon = $('.moon');
$('#first').click(function() {
$moon.addClass('animated first');
});
$('#second').click(function() {
$moon.addClass('animated second');
});
You might want to try with the JQuery keyframe plugin, you can download it here:
https://github.com/Keyframes/jQuery.Keyframes
You can then initialize a set of variables such as height width top and left like this:
var $moon = $('.moon'),
newHeight = '0',
newWidth = '0',
newTop = '0',
newLeft = '0';
And then for the clicks you could try dynamic variables for each click incrementing 40 each time it clicks?
$('#first').click(function() {
newHeight = $moon.height() + 40+'px';
newWidth = $moon.width() + 40+'px';
newTop = $moon.position().top + 80+'px';
newLeft = $moon.position().left + 80+'px';
$moon.removeClass('first');
$moon.removeClass('second');
$.keyframe.define([{
name: 'first',
'0%': {'height': $moon.height()+'px',
'width': $moon.width() +'px',
'left': $moon.position().left+'px',
'top': $moon.position().top+'px'
},
'100%': {'height': newHeight,
'width': newWidth,
'left': newLeft,
'top': newTop
}
}]);
$moon.addClass('first');
});
$('#second').click(function() {
newHeight = $moon.height() + 40+'px';
newWidth = $moon.width() + 40+'px';
newTop = $moon.position().top + 80+'px';
newLeft = $moon.position().left + 80+'px';
$moon.removeClass('first');
$moon.removeClass('second');
$.keyframe.define([{
name: 'second',
'0%': {'height': $moon.height()+'px',
'width': $moon.width()+'px',
'left': $moon.position().left+'px',
'top': $moon.position().top+'px',
},
'100%': {'height': newHeight,
'width': newWidth,
'left': newLeft,
'top': newTop,
}
}]);
$moon.addClass('second');
});
Thought you might give that a try, Leo.
I have an element div in a shape of a ball. What I am trying to do is, when I refresh the page I want to the ball to fall to the bottom of the webpage and then bounce back up to the top of the page.
This is my jQuery function where the ball falls to the bottom of the web page
$(document).ready(function(){
$("div").animate({ top: '+=585'}, 400);
});
Am I using a correct approach? Should I use slideDwon and slideUp instead?
Try utilizing jQuery UI .effect()
$(function() {
var div = $("div");
// `elem`: element to apply bounce effect,
// `n`: number of bounce effects to apply to `elem`
var bounce = function bounce(elem, n) {
var fx = function fx(el) {
return (el || $(this))
.effect({
effect: "bounce",
easing: "swing",
duration: 400,
distance: window.innerHeight
- (el.height() + el.offset().top * 1.5),
direction: "down",
times: 1
}).promise()
};
return fx(elem).then.apply(elem, $.map(Array(n - 1), function() {
return fx(elem)
}));
};
bounce(div, 1).then(function(el) {
// do stuff when bounce effect complete
console.log("complete", el)
});
});
div {
position: relative;
width: 100px;
height: 100px;
background: rgb(212, 98, 44);
border: 2px solid navy;
border-radius: 50%;
}
<link href="//code.jquery.com/ui/1.11.4/themes/smoothness/jquery-ui.css"
rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js">
</script>
<script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
<div></div>
Take advantage of jQuery's animation chainability. Also, you probably shouldn't assume a static value of 585 will be suitable for every screen size. I suggest using calculated values for generating the offsets, check this fiddle:
$(document).ready(function () {
var viewportH = $(window).height();
var elem = $('div');
var elemH = elem.height();
elem.animate({
top: '+=' + (viewportH - elemH) // bottom of screen
}, 400).animate({
top: '-=' + (viewportH - elemH) // original position
});
});
Using this HTML :
<div id="myDiv" class="myRelativeDiv">test</div>
1st step is to set the position of your div as "relative" :
.relative {
position:relative;
}
2nd step is animate with Jquery (You can chain many animate):
$(function() {
$("#myDiv").animate({ top: '+=585'}, 400).animate({ top: '0'}, 400);
});
JsFiddle
$(document).ready(function(){
$("div").animate({ top: '+=585'}, 400);
setTimeout(
function()
{
$("div").animate({ top: '-=585'}, 400);
}, 400);
});
My first question here. :)
I'm looking for a transitions between two images where the image first shrinks in a circle shape and then the circle grows again containing the other image. It's hard to explain, and I may be using the wrong words, because I can't find anything about it on the Interwebz.
I'm talking about an effect like the Loony Toons ending.
http://www.youtube.com/watch?v=ZuYIq-J5l9I
That shrinking-to-black, can it be done in JavaScript/JQuery?
TL:DR
- Cross-browser: [**See a working demo
here**](http://jsfiddle.net/lthibodeaux/8DSjz/).
Well, mostly working... and
cross-browser. Could do worse. ;]
- Purely CSS3 Solution: [**See a working demo
here**](http://jsfiddle.net/lthibodeaux/8DSjz/16/)
How do I even begin to describe this one? It would be a lot easier if the CSS 2 clip standard supported anything besides a "rect" value, namely a "circle" or "ellipse" but... since that doesn't exist, I've done my best to piece something together that will do what you're asking. The caveats are many. One is that this is only going to work on something with a solid color background in the event you wanted the picture to clip to the background. Another is that while I've tried to account for the CSS update timing across browsers, the rendering still isn't "perfect." My initial approach was to simply animate the clip on the image that was getting replaced, but that didn't work due to the way updates were made to the clipping via the easing function in the plugin I located. The final approach is below.
The Approach
The concept is to set the image as a background-image property of a container like a <div> with a background-position of center center, and the position of the container to relative, or anything non-static. The next is to generate the clipping elements as children of the container. The first is a position: absolute clipping circle image of the color of your background, either transparent PNG or GIF (I prefer the former), and the next four are divs, also with absolute positions that have left, right, top, and bottom attributes set to 0 for each of the respective sides they will clip. The idea is to animate the top, left, width, and height of the clipping circle image and synch up the width and height of the clipping divs using the step callback option of the .animate() call by matching them to the current left and top values. Between animations, you change the background-image of the container to the new image and then start the animation back in the opposite direction.
This required a little finessing in IE7, 8, and Webkit browsers as the animation clipped much more cleanly in Firefox and IE9. This would be the adjust variable you'll see in the working demo.
The sample code is below:
The Markup
<div class="imageContainer image1">
<img class="clip" src="clipCircle.png" />
<div class="top fill"></div>
<div class="left fill"></div>
<div class="right fill"></div>
<div class="bottom fill"></div>
</div>
The CSS
div.imageContainer
{
background-position: center;
width: 300px;
height: 300px;
position: relative;
}
img.clip
{
width: 100%;
height: 100%;
position: absolute;
}
div.fill
{
position: absolute;
background-color: White;
}
div.left, div.right
{
height: 100%;
top: 0;
width: 0;
}
div.left
{
left: 0;
}
div.right
{
right: 0;
}
div.top, div.bottom
{
width: 100%;
left: 0;
height: 0;
}
div.top
{
top: 0;
}
div.bottom
{
bottom: 0;
}
The Script
var speed = 1000;
$clip = $("img.clip");
$clip.animate({
top: $clip.parent().height() / 2,
left: $clip.parent().width() / 2,
width: 0,
height: 0
}, {
duration: speed,
step: function(now, fx) {
switch (fx.prop) {
case "top":
$("div.top").css("height", now);
$("div.bottom").css("height", now + adjust);
break;
case "left":
$("div.left").css("width", now);
$("div.right").css("width", now + adjust);
}
},
complete: function() {
$(this).parent().addClass("image2");
$(this).animate({
top: 0,
left: 0,
width: $clip.parent().width(),
height: $clip.parent().height()
}, {
duration: speed,
step: function(now, fx) {
switch (fx.prop) {
case "top":
$("div.top").css("height", now);
$("div.bottom").css("height", now + adjust);
break;
case "left":
$("div.left").css("width", now);
$("div.right").css("width", now + adjust);
}
},
complete: function() {
$("div.imageContainer > *").removeAttr("style");
}
});
}
});
EDIT:
The CSS3 Solution
When cross-browser compatibility is less of a concern, CSS3 is an option (although I'd probably suggest seeing what can be done with the new HTML5 Canvas for this kind of animation). There are a couple things to note:
The image must be inside a container in order to allow us to clip toward its center rather than its top left corner.
The border-radius attribute will not clip the child images inside a container. For this reason, the image must become the background-image attribute of the container.
jQuery does not currently animate border-radius correctly. You can either replace the current jQuery animate functionality for that attribute or build a custom border-radius animation object to make jQuery more well-behaved. I have opted for the latter. Each corner's border-radius must be animated separately.
The animation in or out consists of two separate segments, and as a result the "linear" easing function is probably best used for cleanest results.
The method is commented inline below:
The Markup
<div class="imageContainer image1">
</div>
The CSS
div.imageContainer
{
background-position: 0px 0px;
background-repeat: no-repeat;
width: 300px;
height: 300px;
position: absolute;
top: 0;
left: 0;
}
div.image1
{
background-image: url(/images/myFirstImage.png);
}
div.image2
{
background-image: url(/images/mySecondImage.png);
}
The Script
// Total animation speed in or out will be speed * 1.5
var speed = 600;
// Store a reference to the object to be clipped
var $clip = $("div")
// A function to build a mapping object for border radius parameters
var buildRadiusObj = function(value) {
// Dimension an option object
var opts = {};
// Use specialized Mozilla CSS attributes when needed
var attributes = $.browser.mozilla ?
["-moz-border-radius-topleft",
"-moz-border-radius-bottomleft",
"-moz-border-radius-topright",
"-moz-border-radius-bottomright"] :
["border-top-left-radius",
"border-bottom-left-radius",
"border-top-right-radius",
"border-bottom-right-radius"];
// Build the option object
$.each(attributes, function(i, key) {
opts[key] = value;
});
// Return the result
return opts;
}
$clip.animate(buildRadiusObj($clip.width() * 0.5), { // Animate the border radius until circular
duration: speed * 0.5,
easing: "linear"
}).animate({ // Resize and reposition the container
width: 0,
left: $clip.width() / 2,
height: 0,
top: $clip.height() / 2
}, {
duration: speed,
easing: "linear",
step: function(now, fx) { // Synch up the background-position
if (fx.prop == "top") {
$(this).css("background-position", "-" + $(this).css("top") + " -" + $(this).css("left"));
}
},
complete: function() { // Swap the image
$(this).addClass("image2");
}
}).animate({ // Restore position and size
width: $clip.width(),
left: 0,
height: $clip.height(),
top: 0
}, {
duration: speed,
easing: "linear",
step: function(now, fx) { // Synch the background-position
if (fx.prop == "top") {
$(this).css("background-position", "-" + $(this).css("top") + " -" + $(this).css("left"));
}
},
complete: function() { // Remove inline styles but reapply border-radius
$(this).removeAttr("style").css(buildRadiusObj($clip.width() * 0.5));
}
}).animate(buildRadiusObj(0), { // Restore border-radius to block
duration: speed * 0.5,
easing: "linear",
complete: function() {
$(this).removeAttr("style"); // Remove inline styles
}
});
Again, the demo is located here.
I came this across, I hope it is interesting: http://www.netzgesta.de/transm/. The transition circles_out with one circle could do the job I think.
Here you go. http://jquery.malsup.com/cycle/ Check out the zoom. Something can be worked out with the circle part.
I tried some more and came up with the idea of using a <canvas> element.
Please see the result at: http://jsfiddle.net/3MG8e/2/.
var cv = $('canvas')[0];
var ctx = cv.getContext('2d');
ctx.fillStyle = 'black';
var int = null;
var t = -1;
var amount = 50;
var time = 1000;
var size = 0;
var im = new Image();
im.src = "http://burzak.com/proj/fxcanvas/docs/images/mario2.png";
im.onload = function() {
size = im.width;
int = setInterval(update, time / amount);
}
function update() {
if(++t >= amount) {
clearInterval(int);
}
ctx.fillRect(0, 0, cv.width, cv.height);
ctx.beginPath();
ctx.arc(size/2, size/2,
size/2 - t * (size/2) / amount,
0, Math.PI*2,
false);
ctx.clip();
ctx.drawImage(im, 0, 0, size, size);
}