How do I make an ease function for animation in javascript? - javascript

I know there is already a function in jquery that allows you to animate. But, I want to know how make an element ease into a position I want it to go with javascript. I have a simple function where if you click on a button a div will appear and it will slide down a little bit. The problem is that the animation of the sliding down is a bit choppy sometimes, but other times its fine. Is there a way to make the animation smooth everytime I click the button?
Snippet
document.querySelector('div#ex2 button').onclick = function() {
var counter;
// shows the div
document.querySelector('div#reveal').style.display = "block";
// used to decrease bottom position
var dec = 20;
counter = setInterval(moveD, 10);
// moves the div down
function moveD() {
dec -= 2;
document.getElementById('reveal').style.bottom = dec + "px";
if (dec < 1) {
clearInterval(counter);
log('function is done');
document.getElementById('reveal').style.bottom = 0;
} // moveD if
} // function moveD
}; // onclick function
div#reveal {
height: 100px;
width: 300px;
background: purple;
padding: 5px;
position: relative;
bottom: 20px;
display: none;
color: white;
text-align: center;
vertical-align: center;
margin: 10px 0;
}
<div id="ex2">
<h2>Example 2</h2>
<p></p>
<h4>results:</h4>
<button>Click it</button>
<div id="reveal">This will be revealed</div>
</div>

I think you can solve your issue just by using CSS animation honestly.
Keep in mind, you should always use CSS to do something instead of javascript if at any way possible.
w3schools link
Specifically (you can scrolldown a bit) there is an animation-timing-function which you would be interested in.

Check out all these easing functions: https://github.com/danro/jquery-easing/blob/master/jquery.easing.js.
If you want to see them in use check out my animation library at http://nanimation.js.org/.
Check this for more information on the functions and their parameters: jQuery easing function — variables' comprehension.

Related

jQuery isn't working to make navigation icons appear after scrolling past 1vh

I work in a web development environment that uses WordPress. The theme we use is ThemeCo's Pro.
I'm still learning javascript (so please forgive me if I'm really far off), and I'm trying to use jQuery to write a piece of code that will allow an element to appear after scrolling 1vh of the page. Can anyone help me understand why this isn't working? I can't tell if it's my code, or my theme might not be allowing it. The theme itself uses jQuery on the front end, but has a javascript file I may edit, but for the most part, the frontend editor is pretty reliable for code.
I'm using pieces from this question to help me write it, as well as referencing the jQuery library.
$(window).scroll(function() {
var scroll = $(window).scrollTop();
var minH = $(window).height() * 1;
if (scroll >= minH) {
$("#circle-menu").fadeTo(500, 1);
}
else {
$("#circle-menu").fadeTo(500, 0);
}
});
Just to make sure I understand what you're trying to do, I'll quickly reiterate what your code does: Basically, minH is supposed to be 1vh, and if scroll is >= minH, you want #circle-menu to fade in.
That being said, I think we have to look at a couple potential issues with the code above:
1vh is really just 1/100 of the viewport height, which can be calculated as:
// this is 1vh, which is what you're going for
$(window).height() / 100
As opposed to:
// this is 100vh
$(window).height() * 1
The second would be that you're using fadeTo. The difference between fadeIn/fadeOut and fadeTo is that fadeTo doesn't affect an element's display property. It only affects an element's opacity property. This means that if the theme's default value for the menu's display property is set to "none", fadeTo is not going to make it fade into sight. To get around this, in my opinion, it would be better to use fadeIn and fadeOut instead, especially since it doesn't seem like you're trying to control different levels of opacity (which is what fadeTo is really needed for).
I made a quick code snippet to demonstrate the above fixes.
$(window).scroll(function() {
var scroll = $(window).scrollTop();
var vh = $(window).height() / 100;
var minH = vh;
if (scroll >= minH) {
$("#circle-menu").fadeIn(500);
}
else {
$("#circle-menu").fadeOut(500);
}
});
p {
margin-top: 10vh;
height: 150vh;
border: 2px solid #666;
}
#circle-menu {
font-family: 'Segoe UI', verdana, sans-serif;
font-size: 20px;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 50px;
box-shadow: 1px 2px 3px rgba(50,50,50,0.1);
z-index: 1;
display: none;
background-color: steelblue;
color: white;
padding-left: 20px;
padding-top: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="circle-menu">Menu</div>
<p></p>

How can I animate an element from a static layout position to an absolute layout position?

I have a form and inside this form a button. Initially the button is statically positioned at its default position based on usual layout. On an event (in the example below, button click) I want to move it to the center of the form through animation and during this animation doing a horizontal flip (using scale transform) and when the animation is in the middle (when the rendered width is 0) changing the contents of the button to a paragraph that once loaded will show an animation probably done with svg and a link.
This snippet does a part of what I want (everything until the second part of the flip with changing the contents and resizing the button to be bigger), but without an initial static position from which to start the animation:
var form = $("form")
var button = $("button")
button.on("click", function(){
var x = (form.outerWidth() - button.outerWidth()) / 2;
var y = (form.outerHeight() - button.outerHeight()) / 2;
button.css({
transform: `translateX(${x}px) translateY(${y}px) scaleX(0)`
});
})
form {
background: #aaa;
border-radius: 4px;
padding: 20px;
font-size: 25px;
transition: all 0.2s;
margin: 0 auto;
width: 300px;
position: relative;
}
button {
background: #0084ff;
border: none;
border-radius: 5px;
padding: 8px 14px;
font-size: 15px;
color: #fff;
position: absolute;
left: 0;
top: 0;
transition: transform 1s;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form>
<p>Hello World</p>
<button onclick="return false;">Do something</button>
</form>
(https://jsfiddle.net/silviubogan/L1ogpf6a/)
How can I achieve what I want in the most correct manner? Please note that the rest of the form should remain in place.
Thank you.
There's two ways you can do this. First is using setTimeout (reference) with 1000ms as a parameter, since your css animation lasts 1 second, and a callback function that displays the SVG. The second is using jQuery animate (reference) instead of css, and using the parameter complete to show your SVG. Since you are already using css for the animation, let's go with the first option:
button.on("click", function(){
// hide button
window.setTimeout(transform2, 1000);
})
function transform2() {
// change contents
// resize button
}
Example fiddle: https://jsfiddle.net/eynL91qu/

JS Hover Over One Item to Make Another Move

I've got a simple text button with an image of an arrow next to it. I'm wanting the arrow image to move when someone hovers over the button.
I currently have this working in one instance with JS 'document.getElementById...', but I have several buttons across my site that I'd like to have the same behavior. My first thought would be to use a class instead of an id, and use the same functions.
For whatever reason, document.getElementsByClassName doesn't work - even in one instance.
Here's a simpler version to demonstrate - View on Codepen: https://codepen.io/sdorr/pen/JxYNpg
HTML
<HTML>
hover over me
<div id="block"></div>
hover over me
<div class="block"></div>
CSS
* {
margin: 0;
padding: 0;
}
.button {
color: #000000;
text-decoration: none;
background-color: cyan;
margin: 0;
display: block;
width: 300px;
padding: 20px;
text-align: center;
}
#block {
width: 30px;
height: 30px;
background-color: red;
}
.block {
width: 30px;
height: 30px;
background-color: green;
}
JS
function move() {
document.getElementById("block").style.marginLeft = "35px";
}
function moveBack() {
document.getElementById("block").style.marginLeft = "0px";
}
function moveAlt() {
document.getElementsByClassName("block").style.marginLeft =
"35px";
}
function moveBackAlt() {
document.getElementsByClassName("block").style.marginLeft =
"0px";
}
First off, why isn't the behavior with a class working but an id works fine?
Secondly, would a class solve this issue and be scalable across all buttons with the same two functions (onmouseover / onmouseout)?
If not, any ideas on a solution? I currently have a solution I found using jQuery that does work, but when hovering over one button, all arrow images move across the site. I don't necessarily mind this behavior because only one button is really in view at a time - but I'm trying to learn JS and solve problems with my own solutions!
I greatly appreciate your desire to learn on your own and not rely on premade solutions. Keep that spirit and you will go places!
When it comes to getElementsById, we know this should work for one element, since the function returns a single Element.
However, what does getElementsByClassName return?
(see: https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName)
It returns an HTMLCollection which you can iterate over to change an single element's style.
So, to get this to work with JavaScript you need to write a function that will be able to identify the particular div.block you want to move. But, this puts you back to where you started, needing some particular identifier, like an id or a dataset value to pass to the function.
Alternately, based on the HTML structure you provide, you could look for nextElementSibling on the a that get's clicked. But I would set up an eventListener rather than adding a JS function as a value to the onmouseenter property.
const btns = document.getElementsByTagName('a');
/*** UPDATE forEach is a NodeList method, and will fail on HTMLCollection ***/
/* this fails -> Sorry! ~~btns.forEach(button=>{~~
/* the following will work
/**********/
for (let i = 0; i < btns.length; i++){
btns[i].addEventListener('mouseenter', function(e) {
//we pass e to the function to get the event and to be able to access this
const block = this.nextElementSibling;
block.style.marginLeft = "35px";
})
btns[i].addEventListener('mouseleave', function(e) {
const block = this.nextElementSibling;
block.style.marginLeft = "0";
})
}
But with siblings, there is a CSS-only solution.
We can use the Adjacent Sibling Selector combined with the :hover state selector and no JavaScript is needed, if we are just moving back and forth.
.button:hover+.block {
margin-left: 35px;
}
See the Snipped Below
* {
margin: 0;
padding: 0;
}
.button {
color: #000000;
text-decoration: none;
background-color: cyan;
margin: 0;
display: block;
width: 300px;
padding: 20px;
text-align: center;
}
.block {
width: 30px;
height: 30px;
background-color: green;
}
.button:hover+.block {
margin-left: 35px;
}
hover over me
<div class="block"></div>
hover over me
<div class="block"></div>
As Vecta mentioned, getElementsByClassName returns an array-like. You'll need to do something like this to get the first element:
function moveAlt() {
document.getElementsByClassName("block")[0].style.marginLeft = "35px";
}
function moveBackAlt() {
document.getElementsByClassName("block")[0].style.marginLeft = "0px";
}
However a better solution might be to use document.querySelector, which operates similarly to jQuery's $() syntax:
function moveAlt() {
document.querySelector(".block").style.marginLeft = "35px";
}
function moveBackAlt() {
document.querySelector(".block").style.marginLeft = "0px";
}

resizing a div element for a timeframe after a button is clicked. Do i use javascript or is there an easier way

Hi i a wondering what is the best way to resize a div for a time frame say 5 seconds after a button is clicked. what is the best solution to do this javascript or jquery
You will have to use javascript in order to do anything on the button click.
If it was me - I would add a class to the div on the click, and set a time out to remove the class. The class would have the altered styling that would affect the size of the div. In this demo - I am making the target div twice as big for a time of 2 seconds and then reoving the class to return the div back to ormal.
Note that there are numerous ways to alter the size of the div, but you will need to use javascript to trigger them. You don't need the jQuery library just this though- straight js can do it. You should investigate some of the funky CSS ways to affecting DOM elements to get a nice smooth transition or altertion.
function alterSize(type) {
var targetDiv = document.querySelector("#target-div");
targetDiv.classList.add(type);
setTimeout(function(){
targetDiv.classList.remove(type);
}, 2000)
}
#target-div {
height: 100px;
width: 100px;
border: solid 1px blue;
background: #efefef;
transition: all 0.5s ease-in-out;
}
#target-div.small {
height: 50px;
width: 50px;
}
#target-div.large {
height: 200px;
width: 200px;
}
<button type="button" onclick="alterSize('small')">Click me to decrease the size</button>
<button type="button" onclick="alterSize('large')">Click me to increase the size</button>
<hr/>
<div id="target-div">

On mobile, how can I keep an orientation change from breaking Jquery touchstart/touchend?

I have a small sample app here: http://codepen.io/DouglasGlover/full/OPpMaV/
This is a mobile-only experience (though it technically functions on desktop as well). Only concerned about mobile here.
The intended behavior is that a user touches their phone, and holds their finger down on the phone (anywhere on the screen). As they do this, the counter goes up. When they let their finger come off the phone, it stops the counter.
There is a use case where a user may (perhaps accidentally) rotate their phone just enough that the site's orientation switches. Currently, if that happens, the counter continues to count infinitely upwards. Subsequent touches initiate a second touch event, which makes it go faster (I can deal with that, fixing the initial issue should fix this).
So my problem seems to be that upon switching orientation, the touch event "dies". So "touchstart" fires initially, and I'm waiting for a "touchend" which never gets to fire.
Ideally, the user can touch the phone, then rotate it without consequence (and without breaking the experience).
Here's the prototype code as it stands now...
HTML:
<div class="touchspace"></div>
<div class="ls">
<div class="counter">0</div>
</div>
<div class="pt">
<div class="counter">0</div>
</div>
CSS:
body{ margin: 0; }
.ls, .pt{ display: block; width: 100vw; height: 100vh; }
.ls{ background: lightblue; }
.pt{ background: lightgreen; }
.counter{ display: block; position: relative; top: 10%; font-weight: bold; color: white; font-size: 20vw; width: 20%; margin: 0 auto; }
.touchspace{ display: block; position: absolute; bottom: 0; right: 0; background: transparent; z-index: 999; background: red; width: 500vw; height: 500vh; opacity: .5; }
#media all and (orientation:landscape){ .ls{ display: none; } }
#media all and (orientation:portrait){ .pt{ display: none; } }
JS:
var counter = 0,
interval;
$(".touchspace").bind("touchstart mousedown",function(){
interval = window.setInterval(function(){
counter++;
$(".counter").html(counter);
}, 1000);
});
$(".touchspace").bind("touchend mouseup",function(){
window.clearInterval(interval);
});
Can you bind the orientationchange event to trigger an end and a start, or will that cause too much of a break in the user experience.
something like:
$(window).on('orientationchange', function () {
$('.touchspace').trigger('touchend');
$('.touchspace').trigger('touchstart');
});
Inside the interval, check if the initial orientation is changed and clear the interval. Not able to test the code as I do not have the environment!
var counter = 0,
isOrientationChanged=false,
interval;
$(".touchspace").bind("touchstart mousedown",function(){
interval = window.setInterval(function(){
counter++;
$(".counter").html(counter);
//check if orientation is changed, clear the interval & reset the flag
if(isOrientationChanged)
{
isOrientationChanged=false;
window.clearInterval(interval);
}
}, 1000);
});
$(".touchspace").bind("touchend mouseup",function(){
window.clearInterval(interval);
});
$(window).on('orientationchange', function () {
isOrientationChanged=true;//mark the flag true
});
I've spend last 2 hours trying to achieve it. It seems that it is unable right now - current prior of art. "orientationchange" loses focus of the element.

Categories