change the margin on each slideToggle() call by x% - javascript

I want to reduce my containers magin step by step when using slideToggle()
$(document).ready(function() {
$("#btn").click(function() {
doIt();
});
});
function doIt() {
var container = $("#c2");
var maxMarginTop = container.css("marginTop").replace('px', '');
var maxMarginBottom = container.css("marginBottom").replace('px', '');
container.slideToggle({
duration: 2000,
progress: function(animation, progress, remainingMilliseconds) {
var newMarginTop = maxMarginTop - (maxMarginTop * progress);
var newMarginBottom = maxMarginBottom - (maxMarginBottom * progress);
container.css("margin-top", newMarginTop);
container.css("margin-bottom", newMarginBottom);
},
complete: function() {
container.remove();
}
});
}
.container {
margin-top: 20px;
margin-bottom: 20px;
height: 20px;
width: 100px;
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="btn">Do it</button>
<div class="container" id="c1">
</div>
<div class="container" id="c2">
</div>
<div class="container" id="c3">
</div>
I have to execute code on each step within the slide function. I calculate the new margin based on the current progress.
So the margin should go from 100% to 0% represented by the progress.
Within the progress function I calculate the new margin and when logging the new values this works fine.
But as you can see nothing happens. When logging the margin value in the complete function nothing changed.
Is it a wrong scope? What is happening there?

The problem with your code is that you have added both top and bottom margin which causes a collapsing margin - ie you only get 20px of margin. Therefore, you may as well start off with one margin and then it will animate properly
Why not do this with css animation:
$(document).ready(function() {
$("#btn").click(function() {
$("#c2").addClass('closed');
});
});
.container {
margin-top: 20px;
/* do not need the bottom margin due to collapsing margins */
height: 20px;
width: 100px;
background: red;
transition: all 2s ease;
}
.container.closed {
height:0;
margin:0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="btn">Do it</button>
<div class="container" id="c1">
</div>
<div class="container" id="c2">
</div>
<div class="container" id="c3">
</div>
If you want to carry on using js animations, just remove one of your margins:
$(document).ready(function() {
$("#btn").click(function() {
doIt();
});
});
function doIt() {
var container = $("#c2");
var maxMarginTop = container.css("marginTop").replace('px', '');
var maxMarginBottom = container.css("marginBottom").replace('px', '');
container.slideToggle({
duration: 2000,
progress: function(animation, progress, remainingMilliseconds) {
var newMarginTop = maxMarginTop - (maxMarginTop * progress);
var newMarginBottom = maxMarginBottom - (maxMarginBottom * progress);
container.css("margin-top", newMarginTop);
},
complete: function() {
container.remove();
}
});
}
.container {
margin-top: 20px;
height: 20px;
width: 100px;
background: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="btn">Do it</button>
<div class="container" id="c1">
</div>
<div class="container" id="c2">
</div>
<div class="container" id="c3">
</div>

Related

Why does the last container flicker?

I'm trying to create a set of div's that will animate on hover. I'm using jQuery and the HoverIntent plugin to animate it.
The HTML
<body>
<div class="wrapper">
<div class="grow" style="background-color:#03045E;"></div>
<div class="grow" style="background-color:#0077B6;"></div>
<div class="grow" style="background-color:#00B4D8;"></div>
<div class="grow" style="background-color:#90E0EF;"></div>
</div>
</body>
... and the JS Code
$(function() {
$('.grow').hoverIntent({
over : function() {
$('.grow').animate({
'width':'15%'
},{duration:400,queue:false});
$(this).animate({
'width':'55%'
},{duration:400,queue:false});
},
out : function() {
//we need to check if the mouse is outside the main object to fire a back to original state. Hence, the mouse out effect on the containers itself should do nothing.
}
});
$('.wrapper').hoverIntent({
out : function() {
$('.grow').animate({
'width':'25%'
});
}
});
});
It is available here - https://jsfiddle.net/be0u3hfx/12/
I cant seem to understand why the last div flickers on hover of any div! Help!?
It's because during the size changes, the widths of the elements will occasionally amount to more than 100% total, and when that happens, the browser briefly wraps the last element, making it appear below the first. To prevent that, add display: flex; to your wrapper's CSS rules.
Fixed code:
$(function() {
$('.grow').hoverIntent({
sensitivity: 1, // sensitivity threshold
interval: 10, // milliseconds for onMouseOver polling interval
timeout: 500, // number = milliseconds delay before onMouseOut
over: function() {
$('.grow').animate({
'width': '15%'
}, {
duration: 400,
queue: false
});
$(this).animate({
'width': '55%'
}, {
duration: 400,
queue: false
});
},
out: function() {}
});
$('.wrapper').hoverIntent({
over: () => {},
out: function() {
$('.grow').animate({
'width': '25%'
});
}
});
});
* {
box-sizing: border-box;
}
body {
background-color: black;
margin: 0 auto;
padding: 10px;
height: 100vh;
width: 100%;
}
.wrapper {
padding: 10px;
height: 100%;
background: #fff;
display: flex;
}
.grow {
box-sizing: border-box;
height: 100%;
/* Original height */
width: 25%;
/* Original width */
float: left;
/* Just for presentation (Not required) */
position: relative;
/* Just for presentation (Not required) */
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.hoverintent/1.10.1/jquery.hoverIntent.min.js"></script>
<div class="wrapper">
<div class="grow" style="background-color:#03045E;"></div>
<div class="grow" style="background-color:#0077B6;"></div>
<div class="grow" style="background-color:#00B4D8;"></div>
<div class="grow" style="background-color:#90E0EF;"></div>
</div>

JQuery ScrollTop doesn't scroll to the right item

I am trying to scroll to an item inside a div container. The scroll to top function works however it seems to overshoot the item.
Javascript
<script>
$(document).ready(function () {
var container = $('#directory'),
scrollTo = $('.highlight_bg');
container.animate({
scrollTop: scrollTo.offset().top - container.offset().top + container.scrollTop()
}, 2000);
});
</script>
HTML:
<div id="directory" class="directory" style="height: calc(100% - 111px)">
<div class="directoryitem"></div>
<div class="directoryitem"></div>
<div class="directoryitem highlight_bg"></div>
<div class="directoryitem"></div>
</div>
So the end is to scroll to the div item with class name highlight_bg
Not sure where am going wrong?
Your Javascript code is actually working. So maybe a CSS issue ?
$(document).ready(function () {
var container = $('#directory'),
scrollTo = $('.highlight_bg');
container.animate({
scrollTop: scrollTo.offset().top - container.offset().top + container.scrollTop()
}, 2000);
});
/* DEMO STYLISING PART */
.directoryitem {
display: block;
height: 90%;
width: 90%;
background-color: #CCC;
border: 5px solid gray;
}
.highlight_bg {
background-color: green;
}
/* SCROLL PART */
html, body {
height: 100%;
width: 100%;
}
.directory {
position: relative;
height: 100%;
width: 100%;
overflow: auto;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="directory" class="directory" style="height: calc(100% - 111px)">
<div class="directoryitem"></div>
<div class="directoryitem"></div>
<div class="directoryitem highlight_bg"></div>
<div class="directoryitem"></div>
</div>

How to process data attribute which is the number of negative?

Welcome! Help me please! Blocks .left when scrolling change a space from 300 to 0; moving from the center to the left. And how to make blocks .right when scrolling changed indent from -300 to 0, moving from the center to the right? Thank you very much for your help!
$(function() {
var $win = $(window),
$rev = $('[data-tr]'),
winH2 = 0,
winSt = 0;
function reveal() {
winSt = $win.scrollTop();
winH2 = $win.height()/2;
$rev.each(function(i, el){
var y = el.getBoundingClientRect().top,
toMiddleMax = Math.max(0, y-winH2),
idealMarg = Math.min(+el.dataset.val, toMiddleMax),
margMin = Math.min(idealMarg, idealMarg * (toMiddleMax/winH2));
$(this).css({transform: el.dataset.tr+"("+ margMin +"px)"});
});
}
$win.on({
"load resize scroll" : reveal
});
});
*{box-sizing:border-box; -webkit-box-sizing:border-box;}
html, body{height:100%; margin:0;}
p {height:250px;}
.left,
.right,
.top {
height: 100px;
width: 100px;
padding: 40px;
margin: 10px;
}
.left {background:red;float:left;}
.right {background:green;float:right;}
.top {background:blue;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p></p>
<div class="left" data-tr="translateX" data-val="300"></div>
<p></p>
<div class="left" data-tr="translateX" data-val="300"></div>
<p></p>
<div class="right" data-tr="translateX" data-val="-300"></div>
<p></p>
<div class="right" data-tr="translateX" data-val="-300"></div>
<p></p>
<div class="top" data-tr="translateY" data-val="300"></div>
<p></p>
<div class="top" data-tr="translateY" data-val="300"></div>
<p></p>

How do I start with the tab expanded (toggle)?

So I am modifying a web page and there is a table on the bottom of the page that starts minimized. When you click the arrow it opens upward to reveal the table. I am attempting to modify it so that it already starts off opened when the page loads.
HTML Snippet:
<div class="row" id="cp-toggle">
<div class="col-sm-12">
<div class="col-sm-2 col-sm-offset-5 toggle-button">
<a><span class="glyphicon glyphicon-chevron-up"></span></a>
</div>
<div class="col-sm-12" style="height: calc(100% - 25px);max-height: 250px;background-color:#d3d3d3;">
<div style="height: 100%;max-height: 250px;">
<div style="height: 25px;padding-top: 4px;">
<div style="float: left;padding-right: 9px;">
<span> Posts: </span> <span id="posts_count"></span>
</div>
</div>
<div style="overflow-y: scroll;height: 100%;max-height: 225px;">
<table id="result_table" class="table" style="display:table;" >
<thead class="result_thead"></thead>
<tbody class="result_tbody"></tbody>
</table>
</div>
</div>
</div>
</div>
</div>
Javascript:
var control_panel= (function(){
var container = $('#cp-toggle div:first-child');
var btn = $('#cp-toggle div:first-child').find("div").first();
var table_panel = $('#cp-toggle div:first-child div:nth-child(2)').first();
var open_css = "glyphicon-chevron-up";
var close_css = "glyphicon-chevron-down";
var open = function(){
container.find("span").first().switchClass(open_css, close_css);
var h = table_panel.height() + 25;
container.css("top", "calc(100% - "+ h +"px)");
};
var close = function(){
container.find("span").first().switchClass(close_css, open_css);
container.css("top", "calc(100% - 25px)")
};
var isOpen = function(){
return _.contains(container.find("span").first().attr('class').split(/\s+/), close_css);
};
var toggle = function(){
if (isOpen()){
close();
} else {
open();
}
};
btn.on('click', toggle);
return {
open: open,
close: close,
toggle: toggle,
isOpen : isOpen
};
}());
CSS Snippet:
#cp-toggle > div:first-child {
top: calc(100% - 25px);
position: fixed;
z-index: 25;
}
.toggle-button {
height: 25px;
padding-top: 3px;
background-color: #d3d3d3;
border-top-right-radius: 7px;
border-top-left-radius: 7px;
text-align: center;
cursor: pointer;
}
#cp-toggle a {
color: #111;
}
#cp-toggle a:hover {
color: #777;
}
.tab-pane { height: 100%;}
#email-body { height: calc(100% - 80px); }
.body-view { height: 100%; overflow-y: scroll; }
.marked {
color: #ffd700;
}
.marked:hover {
color: #ffd700;
}
I have tried modifying the javascript to call control_panel.open(); at the end. I have tried altering the toggle to start with open();. None of these seem to have any effect on the code. I am not sure if I am looking in the correct area or if I am doing something incorrectly.
Try this (you tried something similar in a comment, but I'll explain in a minute...):
<script>
window.addEventListener('load', function() {
control_panel.open();
});
</script>
The problem with your original attempt...
<script>onLoad=control_panel.open();</script>
... was that it was setting a variable called 'onLoad' with the value of whatever was returned by running the function control_panel.open(), which it did immediately instead of waiting until the page was loaded. Instead, in my example I'm setting an 'onload' listener on the window, so that when the window finishes loading, then it'll run the control_panel.open() function that it is now aware of.

Count back percentage using JQuery

I have the code below where I'd like to the numbers count back to 0% once hover the object out. Also I can't figure our how to make the value disappear again as it was on load. Could you please help me solve this.
Thanks in advance.
HTML
<div class="container">
<div class="fill" data-width="80%"></div>
</div>
<div class="container">
<div class="fill" data-width="50%"></div>
</div>
CSS
.container {
position: relative;
width: 300px;
height: 30px;
background-color: blue;
margin: 10px auto;
}
.fill {
height: 100%;
width: 0;
background-color: red;
line-height: 30px;
text-align: left;
z-index: 1;
text-align: right;
}
JQuery
$(function() {
$('.container').hover( function(){
var width=$(this).find(".fill").data('width');
$(this).find(".fill").animate({ width: width }, {
duration:800,
step: function(now, fx) {
$(this).html(Math.round(now) + '%');
}
});
},
function(){
$(this).find(".fill").animate({ "width": "0px" }, 800);
});
});
jsFiddle http://jsfiddle.net/zp8pe069/
jsBin demo
CSS: set overflow: hidden to .fill to prevent the text being visible after the animation ends.
HTML: remove % from the data attribute
JS and here you go. all you need:
$('.container').hover(function( e ){
var $fill = $(this).find(".fill");
var width = $fill.data('width');
$fill.stop().animate({width: e.type=="mouseenter" ? width+"%" : "0%" }, {
duration : 800,
step : function(now) {
$(this).html(Math.round(now) + '%') ;
}
});
});
Note also the use of the .stop() method, if you hover multiple time hysterically :) it'll prevent endless animations.

Categories