Here is my JsFiddle
I want to apply background-color change property to circle when the window slides. Like in the beginning only first circle will have background-color. and when the images slides to second screen the second circle will have only color.
Can anybody guide me how to achieve that.
JQuery:
$(document).ready(function () {
setInterval(function () {
var A = $('.gallery').scrollLeft();
if (A < 993) {
$('.gallery').animate({
scrollLeft: '+=331px'
}, 300);
}
if (A >= 993) {
$('.gallery').delay(400).animate({
scrollLeft: 0
}, 300);
}
}, 3000);
});
Here's a simple solution of your problem: http://jsfiddle.net/pjvCw/44/ but....
The way you're doing galleries is quite wrong.
You have a really sensitive CSS full of margin bugs (see in CSS code),
you calculate all by hand, which will just complicate your life one day if you'll get to add images, change widths etc...
Your buttons are positioned really wrongly, and again you don't even need to manually add them in your HTML. Let jQuery do all the job for you:
Calculate margins, widths,
Get the number of slides
generate buttons,
Make your buttons clickable
Pause gallery on mouseenter (loop again on mouseleave)
LIVE DEMO
This is the way you should go with your slider:
HTML:
<div class="galleryContainer"> <!-- Note this main 'wrapper' -->
<div class="gallery">
<div class="row">
<!-- ..your images.. -->
</div>
<div class="row">
<!-- ..your images.. -->
</div>
</div>
<div class="content-nav-control"></div> <!-- Let jQ create the buttons -->
</div>
Note the general gallery wrapper, it allows you with this CSS to make your buttons parent not move with the gallery.
CSS:
In your code, using display:inline-block; adds 4px margin to your elements, ruining your math. So you just need to apply font-size:0; to remove that inconvenience.
As soon I did that the math was working and the right width was than 340px, having 5px border for your images and 20px margin.
.galleryContainer{
/* you need that one
// to prevent the navigation move */
position:relative; /* cause .content-nav-control is absolute */
background-color: #abcdef;
width:340px; /* (instead of 350) now the math will work */
height: 265px;
}
.gallery{
position:relative;
overflow: hidden; /* "overflow" is enough */
width:340px; /* (instead of 350) now the math will work */
height: 265px;
}
.gallery .row {
white-space: nowrap;
font-size:0; /* prevent inline-block 4px margin issue */
}
.gallery img {
display: inline-block;
margin-left: 20px;
margin-top: 20px;
}
.normalimage {
height: 80px;
width: 50px;
border: 5px solid black;
}
.wideimage {
height: 80px;
width: 130px;
border: 5px solid black;
}
img:last-of-type {
margin-right:20px;
}
.content-nav-control {
position: absolute;
width:100%; /* cause it's absolute */
bottom:10px;
text-align:center; /* cause of inline-block buttons inside*/
font-size:0; /* same trick as above */
}
.content-nav-control > span {
cursor:pointer;
width: 20px;
height: 20px;
display: inline-block;
border-radius: 50%;
border:1px solid #000;
box-shadow: inset 0 0 6px 2px rgba(0,0,0,.75);
margin: 0 2px; /* BOTH MARGINS LEFT AND RIGHT */
}
.content-nav-control > span.active{
background:blue;
}
And finally:
$(function () { // DOM ready shorty
var $gal = $('.gallery'),
$nav = $('.content-nav-control'),
galSW = $gal[0].scrollWidth, // scrollable width
imgM = parseInt($gal.find('img').css('marginLeft'), 10), // 20px
galW = $gal.width() - imgM, // - one Margin
n = Math.round(galSW/galW), // n of slides
c = 0, // counter
galIntv; // the interval
for(var i=0; i<n; i++){
$nav.append('<span />'); // Create circles
}
var $btn = $nav.find('span');
$btn.eq(c).addClass('active');
function anim(){
$btn.removeClass('active').eq(c).addClass('active');
$gal.stop().animate({scrollLeft: galW*c }, 400);
}
function loop(){
galIntv = setInterval(function(){
c = ++c%n;
anim();
}, 3000);
}
loop(); // first start kick
// MAKE BUTTONS CLICKABLE
$nav.on('click', 'span', function(){
c = $(this).index();
anim();
});
// PAUSE ON GALLERY MOUSEENTER
$gal.parent('.galleryContainer').hover(function( e ){
return e.type=='mouseenter' ? clearInterval(galIntv) : loop() ;
});
});
"- With this solution, What can I do now and in the future? -"
Nothing! just freely add images into your HTML and play, and never again have to take a look at your backyard :)
Try this: http://jsfiddle.net/yerdW/1/
I added a line that gets the scrollLeft and divides it by your width (331px) to get the position and use that to select the 'active' circle:
$(".circle").removeClass("coloured");
position = Math.ceil($(".gallery").scrollLeft()/331 + 2);
if(position > $(".circle").length){
position = 1; // yes...
}
$(".content-nav-control div:nth-child("+position+")").addClass("coloured");
Red background for active circle:
.coloured {
background : red;
}
Note that you should initialise with the first circle already having the .coloured class applied.
Here you go: http://jsfiddle.net/pjvCw/41/
i added new class
.selected
{
background-color: red;
}
and modified some js code
Here is your jsfiddle edited http://jsfiddle.net/pjvCw/45/
var scrolled = 0;
var circles = $(".circle");
var colorCircle = function(index) {
for(var i=0; i<circles.length; i++) {
if(i == index) {
circles.eq(i).css("background-color", "rgba(255, 0, 0, 1)");
} else {
circles.eq(i).css("background-color", "rgba(255, 0, 0, 0)");
}
}
}
$(document).ready(function () {
setInterval(function () {
var A = $('.gallery').scrollLeft();
if (A < 993) {
$('.gallery').animate({
scrollLeft: '+=331px'
}, 300);
colorCircle(++scrolled);
}
if (A >= 993) {
$('.gallery').delay(400).animate({
scrollLeft: 0
}, 300);
colorCircle(scrolled = 0);
}
}, 3000);
colorCircle(0);
});
I added a transition to the .circle class, so it looks a little bit better:
.circle {
width: 20px;
height: 20px;
display: inline-block;
border-radius: 50%;
border:1px solid #000;
box-shadow: inset 0 0 6px 2px rgba(0,0,0,.75);
margin-right: 5px;
transition: background-color 700ms;
-webkit-transition: background-color 700ms;
}
Related
I'm attempting to mimic the following widget with HTML/CSS/JavaScript:
https://gyazo.com/76bee875d35b571bd08edbe73ead12cb
The way that I have it set up is the following:
I have a bar with a background color that has a gradient from red to green which is static.
I then have two blinders that is supposed to represent the negative space to give the illusion that the colored bars are animating (in reality, the blinders are simply sliding away)
I did it this way because I figured it might be easier instead of trying to animate the bar going in both directions, but now I'm not so sure lol. One requirement that I'm trying to keep is that the animation only deals with transform or opacity to take advantage of optimizations the browser can do (as described here: https://hacks.mozilla.org/2016/08/animating-like-you-just-dont-care-with-element-animate/)
The example has a few buttons to help test various things. The "Random positive" works great, and is exactly what I want. I haven't quite hooked up the negative yet tho because I'm not sure how to approach the problem of transitioning from positive to negative and vice-versa.
Ideally, when going from a positive to a negative, the right blinder will finish at the middle, and the left blinder will pick up the animation and finish off where it needs to go.
So for example, if the values is initially set to 40%, and the then set to -30%, the right blinder should animate transform: translateX(40%) -> transform: translateX(0%) and then the left blinder should animate from transform: translateX(0%) -> transform: translateX(-30%) to expose the red.
Also, the easing should be seamless.
I'm not sure if this is possible with the setup (specifically keeping the easing seamless, since the easing would be per-element, I think, and can't "carry over" to another element?)
Looking for guidance on how I can salvage this to produce the expected results, or if there's a better way to deal with this.
Note: I'm using jquery simply for ease with click events and whatnot, but this will eventually be in an application that's not jquery aware.
Here's my current attempt: https://codepen.io/blitzmann/pen/vYLrqEW
let currentPercentageState = 0;
function animate(percentage) {
var animation = [{
transform: `translateX(${currentPercentageState}%)`,
easing: "ease-out"
},
{
transform: `translateX(${percentage}%)`
}
];
var timing = {
fill: "forwards",
duration: 1000
};
$(".blind.right")[0].animate(animation, timing);
// save the new value so that the next iteration has a proper from keyframe
currentPercentageState = percentage;
}
$(document).ready(function() {
$(".apply").click(function() {
animate($("#amount").val());
});
$(".reset").click(function() {
animate(0);
});
$(".random").click(function() {
var val = (Math.random() * 2 - 1) * 100;
$("#amount").val(val);
animate(val);
});
$(".randomPos").click(function() {
var val = Math.random() * 100;
$("#amount").val(val);
animate(val);
});
$(".randomNeg").click(function() {
var val = Math.random() * -100;
$("#amount").val(val);
animate(val);
});
$(".toggleBlinds").click(function() {
$(".blind").toggle();
});
$(".toggleLeft").click(function() {
$(".blind.left").toggle();
});
$(".toggleRight").click(function() {
$(".blind.right").toggle();
});
});
$(document).ready(function() {});
.wrapper {
margin: 10px;
height: 10px;
width: 800px;
background: linear-gradient(to right, red 50%, green 50%);
border: 1px solid black;
box-sizing: border-box;
position: relative;
overflow: hidden;
}
.blind {
height: 100%;
position: absolute;
top: 0;
background-color: rgb(51, 51, 51);
min-width: 50%;
}
.blind.right {
left: 50%;
border-left: 1px solid white;
transform-origin: left top;
}
.blind.left {
border-right: 1px solid white;
transform-origin: left top;
}
<div class="wrapper">
<div class='blind right'></div>
<div class='blind left'></div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js" type="text/javascript"></script>
<input id="amount" type="number" placeholder="Enter percentage..." value='40' />
<button class="apply">Apply</button>
<button class="random">Random</button>
<button class="randomPos">Random Positive</button>
<button class="randomNeg">Random Negative</button>
<button class="toggleBlinds">Toggle Blinds</button>
<button class="toggleLeft">Toggle L Blind</button>
<button class="toggleRight">Toggle R Blind</button>
<button class="reset" href="#">Reset</button>
I've modified your code. Have a look at the code.
let currentPercentageState = 0;
function animate(percentage) {
var animation = [{
transform: `translateX(${currentPercentageState}%)`,
easing: "ease-out"
},
{
transform: `translateX(${percentage}%)`
}
];
var timing = {
fill: "forwards",
duration: 1000
};
if (percentage < 0) {
$(".blind.right")[0].animate(
[{
transform: `translateX(0%)`,
easing: "ease-out"
},
{
transform: `translateX(0%)`
}
], timing);
$(".blind.left")[0].animate(animation, timing);
} else {
$(".blind.left")[0].animate(
[{
transform: `translateX(0%)`,
easing: "ease-out"
},
{
transform: `translateX(0%)`
}
], timing);
$(".blind.right")[0].animate(animation, timing);
}
// save the new value so that the next iteration has a proper from keyframe
//currentPercentageState = percentage;
}
$(document).ready(function() {
$(".apply").click(function() {
animate($("#amount").val());
});
$(".reset").click(function() {
animate(0);
});
$(".random").click(function() {
var val = (Math.random() * 2 - 1) * 100;
$("#amount").val(val);
animate(val);
});
$(".randomPos").click(function() {
var val = Math.random() * 100;
$("#amount").val(val);
animate(val);
});
$(".randomNeg").click(function() {
var val = Math.random() * -100;
$("#amount").val(val);
animate(val);
});
$(".toggleBlinds").click(function() {
$(".blind").toggle();
});
$(".toggleLeft").click(function() {
$(".blind.left").toggle();
});
$(".toggleRight").click(function() {
$(".blind.right").toggle();
});
});
$(document).ready(function() {});
.wrapper {
margin: 10px;
height: 10px;
width: 800px;
background: linear-gradient(to right, red 50%, green 50%);
border: 1px solid black;
box-sizing: border-box;
position: relative;
overflow: hidden;
}
.blind {
height: 100%;
position: absolute;
top: 0;
background-color: rgb(51, 51, 51);
min-width: 50%;
}
.blind.right {
left: 50%;
border-left: 1px solid white;
transform-origin: left top;
}
.blind.left {
border-right: 1px solid white;
transform-origin: left top;
}
<div class="wrapper">
<div class='blind right'></div>
<div class='blind left'></div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js" type="text/javascript"></script>
<input id="amount" type="number" placeholder="Enter percentage..." value='40' />
<button class="apply">Apply</button>
<button class="random">Random</button>
<button class="randomPos">Random Positive</button>
<button class="randomNeg">Random Negative</button>
<button class="toggleBlinds">Toggle Blinds</button>
<button class="toggleLeft">Toggle L Blind</button>
<button class="toggleRight">Toggle R Blind</button>
<button class="reset" href="#">Reset</button>
You need to animate the things in two steps. The first step is to reset the previous state to initial state(which should be set to 0) and in the second step, you need to run the other animation which will actually move it to the destination state.
In order to achive this you can do,
let currentPercentageState = 0;
const animationTiming = 300;
function animate(percentage) {
let defaultTranformVal = [{
transform: `translateX(${currentPercentageState}%)`,
easing: "ease-out"
}, {transform: `translateX(0%)`}];
var animation = [{
transform: `translateX(0%)`,
easing: "ease-out"
},{
transform: `translateX(${percentage}%)`,
easing: "ease-out"
}];
var timing = {
fill: "forwards",
duration: animationTiming
};
if (percentage < 0) {
if(currentPercentageState > 0) {
$(".blind.right")[0].animate(defaultTranformVal, timing);
setTimeout(() => {
$(".blind.left")[0].animate(animation, timing);
}, animationTiming);
} else {
$(".blind.left")[0].animate(animation, timing);
}
}
if(percentage > 0) {
if(currentPercentageState < 0) {
$(".blind.left")[0].animate(defaultTranformVal, timing);
setTimeout(() => {
$(".blind.right")[0].animate(animation, timing);
}, animationTiming);
} else {
$(".blind.right")[0].animate(animation, timing);
}
}
// save the new value so that the next iteration has a proper from keyframe
currentPercentageState = percentage;
}
Here, you will see we have two transformations. The first one defaultTranformVal will move the currentPercentageState to zero and then the other one which will move from 0 to percentage.
You need to handle a couple of conditions here. The first one is if you are running it the first time(means there is no currentPercentageState), you don't need to run defaultTranformVal. If you have currentPercentageState then you need to run defaultTranformVal and then run the second animation.
Note:- You also need to clear the timeout in order to prevent the memory leak. This can be handle by storing the setTimout return value and then when next time it's running clear the previous one with the help of clearTimeout.
Here is the updated codepen example:-
https://codepen.io/gauravsoni119/pen/yLeZBmb?editors=0011
EDIT: I actually did manage to solve this!
let easing = "cubic-bezier(0.5, 1, 0.89, 1)";
let duration = 1000;
let easeReversal = y => 1 - Math.sqrt((y-1)/-1)
https://codepen.io/blitzmann/pen/WNrBWpG
I gave it my own cubic-bezier function of which I know the reversal for. The post below and my explanation was based on an easing function using sin() which isn't easily reversible. Not only that, but the built in easing function for ease-out doesn't match the sin() one that I had a reference for (I'm not really sure what the build in one is based on). But I realized I could give it my own function that I knew the reversal for, and boom, works like a charm!
This has been a very informative experience for me, I'm glad that I've got a solution that works. I still think I'll dip my toes in the other ideas that I had to see which pans out better in the long term.
Historical post:
So, after a few nights of banging my head around on this, I've come to the conclusion that this either isn't possible the way I was thinking about doing it, or if it is possible then the solution is so contrived that it's probably not worth it and I'd be better off developing a new solution (of which I've thought of one or tow things that I'd like to try).
Please see this jsfiddle for my final "solution" and a post-mortem
https://jsfiddle.net/blitzmann/zc80p1n4/
let currentPercentageState = 0;
let easing = "linear";
let duration = 1000;
function animate(percentage) {
percentage = parseFloat(percentage);
// determine if we've crossed the 0 threshold, which would force us to do something else here
let threshold = currentPercentageState / percentage < 0;
console.log("Crosses 0: " + threshold);
if (!threshold && percentage != 0) {
// determine which blind we're animating
let blind = percentage < 0 ? "left" : "right";
$(`.blind.${blind}`)[0].animate(
[
{
transform: `translateX(${currentPercentageState}%)`,
easing: easing
},
{
transform: `translateX(${percentage}%)`
}
],
{
fill: "forwards",
duration: duration
}
);
} else {
// this happens when we cross the 0 boundry
// we'll have to create two animations - one for moving the currently offset blind back to 0, and then another to move the second blind
let firstBlind = percentage < 0 ? "right" : "left";
let secondBlind = percentage < 0 ? "left" : "right";
// get total travel distance
let delta = currentPercentageState - percentage;
// find the percentage of that travel that the first blind is responsible for
let firstTravel = currentPercentageState / delta;
let secondTravel = 1 - firstTravel;
console.log("delta; total values to travel: ", delta);
console.log(
"firstTravel; percentage of the total travel that should be done by the first blind: ",
firstTravel
);
console.log(
"secondTravel; percentage of the total travel that should be done by the second blind: ",
secondTravel
);
// animate the first blind.
$(`.blind.${firstBlind}`)[0].animate(
[
{
transform: `translateX(${currentPercentageState}%)`,
easing: easing
},
{
// we go towards the target value instead of 0 since we'll cut the animation short
transform: `translateX(${percentage}%)`
}
],
{
fill: "forwards",
duration: duration,
// cut the animation short, this should run the animation to this x value of the easing function
iterations: firstTravel
}
);
// animate the second blind
$(`.blind.${secondBlind}`)[0].animate(
[
{
transform: `translateX(${currentPercentageState}%)`,
easing: easing
},
{
transform: `translateX(${percentage}%)`
}
],
{
fill: "forwards",
duration: duration,
// start the iteration where the first should have left off. This should put up where the easing function left off
iterationStart: firstTravel,
// we only need to carry this aniamtion the rest of the way
iterations: 1-firstTravel,
// delay this animation until the first "meets" it
delay: duration * firstTravel
}
);
}
// save the new value so that the next iteration has a proper from keyframe
currentPercentageState = percentage;
}
// the following are just binding set ups for the buttons
$(document).ready(function () {
$(".apply").click(function () {
animate($("#amount").val());
});
$(".reset").click(function () {
animate(0);
});
$(".random").click(function () {
var val = (Math.random() * 2 - 1) * 100;
$("#amount").val(val);
animate(val);
});
$(".randomPos").click(function () {
var val = Math.random() * 100;
$("#amount").val(val);
animate(val);
});
$(".randomNeg").click(function () {
var val = Math.random() * -100;
$("#amount").val(val);
animate(val);
});
$(".flipSign").click(function () {
animate(currentPercentageState * -1);
});
$(".toggleBlinds").click(function () {
$(".blind").toggle();
});
$(".toggleLeft").click(function () {
$(".blind.left").toggle();
});
$(".toggleRight").click(function () {
$(".blind.right").toggle();
});
});
animate(50);
//setTimeout(()=>animate(-100), 1050)
$(function () {
// Build "dynamic" rulers by adding items
$(".ruler[data-items]").each(function () {
var ruler = $(this).empty(),
len = Number(ruler.attr("data-items")) || 0,
item = $(document.createElement("li")),
i;
for (i = -11; i < len - 11; i++) {
ruler.append(item.clone().text(i + 1));
}
});
// Change the spacing programatically
function changeRulerSpacing(spacing) {
$(".ruler")
.css("padding-right", spacing)
.find("li")
.css("padding-left", spacing);
}
changeRulerSpacing("30px");
});
.wrapper {
margin: 10px auto 2px;
height: 10px;
width: 600px;
background: linear-gradient(to right, red 50%, green 50%);
border: 1px solid black;
box-sizing: border-box;
position: relative;
overflow: hidden;
}
.blind {
height: 100%;
position: absolute;
top: 0;
background-color: rgb(51, 51, 51);
min-width: 50%;
}
.blind.right {
left: 50%;
border-left: 1px solid white;
transform-origin: left top;
}
.blind.left {
border-right: 1px solid white;
transform-origin: left top;
}
#buttons {
text-align: center;
}
/* Ruler crap */
.ruler-container {
text-align: center;
}
.ruler, .ruler li {
margin: 0;
padding: 0;
list-style: none;
display: inline-block;
}
/* IE6-7 Fix */
.ruler, .ruler li {
*display: inline;
}
.ruler {
display:inline-block;
margin: 0 auto;https://jsfiddle.net/user/login/
background: lightYellow;
box-shadow: 0 -1px 1em hsl(60, 60%, 84%) inset;
border-radius: 2px;
border: 1px solid #ccc;
color: #ccc;
height: 3em;
padding-right: 1cm;
white-space: nowrap;
margin-left: 1px;
}
.ruler li {
padding-left: 1cm;
width: 2em;
margin: .64em -1em -.64em;
text-align: center;
position: relative;
text-shadow: 1px 1px hsl(60, 60%, 84%);
}
.ruler li:before {
content: '';
position: absolute;
border-left: 1px solid #ccc;
height: .64em;
top: -.64em;
right: 1em;
}
<div class="wrapper">
<div class='blind right'></div>
<div class='blind left'></div>
</div>
<div class="ruler-container">
<ul class="ruler" data-items="21"></ul>
</div>
<div id="buttons">
<input id="amount" type="number" placeholder="Enter percentage..." value='-80' />
<button class="apply">Apply</button>
<button class="random">Random</button>
<button class="randomPos">Random Positive</button>
<button class="randomNeg">Random Negative</button>
<button class="flipSign">Flip Sign</button>
<button class="toggleBlinds">Toggle Blinds</button>
<button class="toggleLeft">Toggle L Blind</button>
<button class="toggleRight">Toggle R Blind</button>
<button class="reset" href="#">Reset</button>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.0/jquery.min.js" type="text/javascript"></script>
<hr />
<p><strong>A note</strong> on the attempt made here:</p>
<p>
I was trying to animate a percentage bar that has both positive and negative values. But I set a challenge as well: I wanted to achieve this via animations utilizing only the compositor - which means animating opacity or transform <strong>only</strong> (no color, width, height, position, etc). The ideas presented here were based on the concept of blinds. I have a static element with a background gradient of red to green, then I have two elements that "blind" the user to the background. These blinds, being a simple element, simply slide into and out of place.
</p>
<p>The problem that I ran into was timing the two animations correctly when they switched signage. It's currently working (very well) for linear animation, but as soon as you introduce an easing function it gets wonky. The reason for this is due to the value that I'm using to set the first animation length (iteration, not duration), as well as the second animations start to pick up where the first left off. The value that I was using is the percentage of the total travel distance that each of the blinds will have to do.</p>
<p>So, for example, if you have a value of 50, and go to -80, that's a total travel distance of 130. The first blind travels <code>50 / 130 = ~0.3846</code> of the total distance, and the second blind will travel <code>1 - ~0.3846 = ~0.6154</code> of the total distance.</p>
<p>But, these are not the correct values for the <em>duration</em> of the animation. Instead, these are the percentages of the easing values (the y-axis). To get the duration for these, I would have to find the x value (given the known y value). eg, for an ease-out animation for a value going from 50 to -80, the animation crosses our 0 at ~0.03846, and we would have to solve for x given <code>0.03846 = sin((x * PI) / 2)</code>.</p>
<p>With the help of Wolfram Alpha, I was able to find a few test values this got me much closer to the actual animation, but the blinds always stopped slightly off the mark. I eventually chalked this up to one of two reasons: the fact that the valuess are always going to be approximate and the browser is never going to be 100% accurate, or / and 2) the browser is using a slightly different easing function than I was using for reference. Regardless, being so constrained by the fact that this "animation" relies on two different aniamtions lining up perfectly, I decided to leave this version be and go in a different direction.</p>
<p>
If anyone finds an actual solution to this, please post an answer here: https://stackoverflow.com/questions/62866844/how-to-animate-a-progress-bar-with-negatives-using-element-animate
</p>
Thanks to those that attempted this admittedly tricky problem
Hello I have changed the flip card element from w3schools and added javascript that they will rotate 60px if they are in viewport with that user can understand that there is a textt behind card. It works well on scroll but now I release that hover effekt is not working.Can you please help me?
https://www.w3schools.com/howto/howto_css_flip_card.asp
https://jsfiddle.net/mqbkzLy2/
var x = 0;
$.fn.isInViewport = function() {
var elementTop = $(this).offset().top;
var elementBottom = elementTop + $(this).outerHeight();
var viewportTop = $(window).scrollTop();
var viewportBottom = viewportTop + $(window).height();
return elementBottom > viewportTop && elementTop < viewportBottom;
};
$(window).scroll(function() {
if ($(".flip-card-inner").isInViewport() && x == 0) {
setTimeout(function() {
$(".flip-card-inner").css('transform', 'rotateY(80deg)');
}, 400);
setTimeout(function() {
$(".flip-card-inner").css('transform', 'rotateY(0)');
}, 800);
x++;
console.log(x);
console.log("in");
}
if (!$(".flip-card-inner").isInViewport() && x != 0) {
x = 0;
console.log('No success.');
console.log(x);
console.log("out");
}
});
body {
font-family: Arial, Helvetica, sans-serif;
}
.flip-card {
background-color: transparent;
width: 300px;
height: 300px;
perspective: 1000px;
}
.flip-card-inner {
position: relative;
width: 100%;
height: 100%;
text-align: center;
transition: transform 0.6s;
transform-style: preserve-3d;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
}
.flip-card:hover .flip-card-inner {
transform: rotateY(180deg);
}
.flip-card-front,
.flip-card-back {
position: absolute;
width: 100%;
height: 100%;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
.flip-card-front {
background-color: #bbb;
color: black;
}
.flip-card-back {
background-color: #2980b9;
color: white;
transform: rotateY(180deg);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div style="height:120vh;background-color:yellow;"></div>
<h1>Card Flip with Text</h1>
<h3>Hover over the image below:</h3>
<div class="flip-card">
<div class="flip-card-inner">
<div class="flip-card-front">
<img src="https://upload.wikimedia.org/wikipedia/commons/d/de/Windows_live_square.JPG" alt="Avatar" style="width:300px;height:300px;">
</div>
<div class="flip-card-back">
<h1>John Doe</h1>
<p>Architect & Engineer</p>
<p>We love that guy</p>
</div>
</div>
</div>
that they will rotate 60px if they are in viewport with that user can understand that there is a textt behind card.
Don't use scroll event listener for this, use Intersection Observer (IO) for this.
IO was designed for such problems. With IO you can react whenever an HTML element intersects with another one (or with the viewport)
Check this page, it shows you how to animate an element once it comes into viewport (scroll all the way down). Of course, you can use any animation you want, this is then handled by CSS. This is just an really visible example.
Short recap on what you have to do to get IO to work:
First you have to create a new observer:
var options = {
rootMargin: '0px',
threshold: 1.0
}
var observer = new IntersectionObserver(callback, options);
Here we define that once your target Element is 100% visible in the viewport (threshold of 1) your callback Function is getting executed. Here you can define another percentage, 0.5 would mean that the function would be executed once your element is 50% visible.
Then you have to define which elements to watch
var target = document.querySelector('.flip-card');
observer.observe(target);
Last you need to specify what should happen once the element is visible in your viewport by defining the callback function:
var callback = function(entries, observer) {
entries.forEach(entry => {
// Each entry describes an intersection change for one observed
// here you animate another element and do whatever you like
});
};
If you need to support older browsers, use the official polyfill from w3c.
If you don't want to trigger the animation again when the elements are scrolled again into view a second time then you can also unobserve an element once it's animated.
In my web app, there is a draggable element.
I need to set the left position of this element when the element reaches a certain limit while dragging.
Using jQuery draggable widget, I have access to the position of the element:
function drag(e, ui) {
console.log(ui.position.left);
}
Let say my left attribute is setted to 1100px, I need to set it to 500px and this, without stopping the dragging.
I have three functions: dragStart, drag, and gradEnd.
Currently, I managed to get only one result: when setting ui.position.left = 500; on the drag function (using a condition), the left position is set to 500 but of course, the element is then stuck at 500px. The reason is that every time the drag function is triggered, the left position is setted to 500.
If the code runs only once the line ui.position.left = 500; the position left attribute is set to 500, but directly reset to 1100.
How can I set the left attribute once and for all?
$("#divId").draggable({
drag: drag,
})
function drag(e, ui) {
if (ui.position.top > 50) {
ui.position.left = 100;
}
}
#divId {
height: 70px;
background-color: white;
border: 4px solid #000000;
text-align: center;
color: black;
cursor: grab;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div id="divId">
Bubble
</div>
I am not sure how jQuery Draggable handles things under the hood, but even after setting ui.position.left = 100, it does not register in the event until after dragging has stopped - that is why I opted to check the actual CSS property of the element that is being targeted.
I have also provided an example (closure/functional based) which demonstrates how to handle this without having to check CSS..
First example:
$("#divId").draggable({
drag: drag
});
function drag(e, ui) {
if (ui.position.top > 50) {
$("#container").css('padding-left', '100px');
$(this).css('left', '0px');
}
if (ui.position.left < 0) {
ui.position.left = 0
}
}
#divId {
height: 70px;
background-color: white;
border: 4px solid #000000;
text-align: center;
color: black;
width: 300px;
cursor: grab;
}
#container {
height: 100vh;
width: 1000px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div id="container">
<div id="divId">
Bubble
</div>
</div>
Second example, more of a 'closure based functional approach': does not require you to check CSS..
$("#divId").draggable({
drag: drag()
});
function drag(e, ui) {
let TRIGGER = false, TOP_THRESHOLD = 50, LEFT_POSITION = 100;
return function(e, ui) {
if (TRIGGER) {
ui.position.left = LEFT_POSITION;
} else if (ui.position.top > TOP_THRESHOLD) {
TRIGGER = true;
ui.position.left = LEFT_POSITION;
}
}
}
#divId {
height: 70px;
background-color: white;
border: 4px solid #000000;
text-align: center;
color: black;
cursor: grab;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<div id="divId">
Bubble
</div>
I created this range slider, and i would like to fill the "lower" section of the slider with a green color similar to the blue in the example picture.
I've tried every technique i could find on the web. I read that Internet Explorer supports code for this sort of thing, but most modern browsers will need a hack to achieve this affect. I tried a gradient technique but it seemed a little too hacky for me. Nothing i try sticks.
Does anybody know a simple way to fill the lower fill section? There has to be a way-
https://codepen.io/stinkytofu3311/pen/GmKxoW
var sizeRange = ["11x17 - Starting Price <span>- $19.99</span>", // Store string inside of an Array
"24x36 - Starting Price <span>- $29.99</span>",
"70x90 - Starting Price <span>- $39.99</span>",
"120x50 - Starting Price <span>- $49.99</span>",
"67x18 - Starting Price <span>- $59.99</span>",
"19x30 - Starting Price <span>- $69.99</span>"]
var imageUrl = new Array(); // Store images inside of an Array
imageUrl[0] = 'http://svgshare.com/i/1Ak.svg';
imageUrl[1] = 'http://svgshare.com/i/1AQ.svg';
imageUrl[2] = 'http://svgshare.com/i/1Bb.svg';
imageUrl[3] = 'http://svgshare.com/i/1Am.svg';
imageUrl[4] = 'http://svgshare.com/i/1CG.svg';
imageUrl[5] = 'http://svgshare.com/i/1By.svg';
$('#sliderPrice').html( sizeRange[0] );
$(document).on('input change', '#range-slider', function() { //Listen to slider changes (input changes)
var v=$(this).val(); //Create a Variable (v), and store the value of the input change (Ex. Image 2 [imageURL])
$('#sliderStatus').html( $(this).val() );
$('#sliderPrice').html( sizeRange[v] );
$("#img").prop("src", imageUrl[v]); // Modify the Images attribute src based on the sliders value, and input the value inside the imageURL[v] to display image
});
// ::::: Range Slider Thumb ::::: //
$("#range-slider").on("mousedown", function() { //1. When user clicks their mouse down on the Range-Slider
$(this).removeClass().addClass("thumb-down");//1.1 Remove default class from CSS, and add the class .thumb-down (changes background color)
$(this).addClass("hover-ring");//1.2 Remove default class from CSS, and add the class .hover-ring (changes box-shadow to a green color)
});
$("#range-slider").on("mouseup", function() { //2. When user mouse-up on Range-Slider
$(this).addClass("thumb-up"); //2.1 Changes thumb color back to light green
$(this).addClass("hover-ring-out"); //2.2 Removes Box-Shadow
});
#import url('https://fonts.googleapis.com/css?family=Roboto');
.product-range-wrapper {
displat: -webkit-flex;
displat:flex;
-webkit-flex-direction: column;
flex-direction:column;
max-width:600px;
margin:0px auto;
/*outline: 1px solid purple;*/
}
.product-range-block {
display: -webkit-flex;
display:flex;
-webkit-flex-direction: row;
flex-direction: row;
width:100%;
height:100%;
/*outline: 1px solid red;*/
}
.ref-height-block {
flex-grow:3;
/*background-color:red;*/
}
.size-chart-block {
flex-grow:9;
/*background-color:green;*/
}
.product-range-block img {
width:90%;
/*outline: 1px solid blue;*/
}
#img {
width: 100% !important;
}
/* ::::::::::::::::::::Range Slider Styles::::::::::::::::::::::::: */
.range-slider-block {
margin:0px auto;
width:90%;
}
#range-slider {
padding:40px 0px;
width:100%;
/*outline: 1px solid green;*/
}
/* Remove Range Sliders Default Styles*/
input[type=range]{
-webkit-appearance: none;
}
/* Track */
input[type=range]::-webkit-slider-runnable-track {
height: 10px;
background: #d7d7d7;
border: none;
border-radius: 6px;
}
input[type=range]:focus {
outline: none;
}
/* Thumb */
input[type=range]::-webkit-slider-thumb {
-webkit-appearance: none;
border: none;
height: 30px;
width: 30px;
border-radius: 50%;
background: #46947F;
margin-top: -9px;
transition: box-shadow 0.5s;
}
input[type=range]:hover::-webkit-slider-thumb {
box-shadow: 0 0 0 10pt rgba(190,190,190,0.4);
cursor:pointer;
}
/* JS Styles */
/* Changes Thumb color to darker green when mousedownn */
input[type=range].thumb-down::-webkit-slider-thumb {
background:#316557;
}
/* Changes Thumb color back to light green when mouseup */
input[type=range].thumb-up::-webkit-slider-thumb {
background:#46947F;
}
/* Changes Ring color Green */
input[type=range].hover-ring::-webkit-slider-thumb {
box-shadow: 0 0 0 6pt rgba(70,148,127,0.46);
cursor:pointer;
}
input[type=range].hover-ring-out::-webkit-slider-thumb {
box-shadow: 0 0 0 0pt rgba(0,0,0,0);
cursor:pointer;
}
/* Input Value Styles */
#slider_count {
margin:0px auto;
width:100%;
padding:0px 20px;
text-align:center;
}
#sliderPrice {
font-family: 'Roboto', sans-serif;
font-size:22px;
font-weight:600;
}
#sliderPrice span {
font-weight:600;
color:red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
<div class="product-range-wrapper">
<div class="product-range-block">
<div class="ref-height-block">
<img src="http://svgshare.com/i/1Ba.svg" alt="Product Height Refrence" height="" width="">
</div>
<div class="size-chart-block">
<img src="http://svgshare.com/i/1Ak.svg" style='' id='img'/>
</div>
</div>
<div id="slider_count"><span id="sliderPrice">0</span></div>
<div class="range-slider-block">
<input type="range" id="range-slider" value="0.0" min="0" max="5" step="1" />
</div>
</div>
<div id="slider_count">Slider Value = <span id="sliderStatus">0</span></div>
<br/>
I managed to get a working version here: http://codepen.io/anon/pen/LyxYVY
var sheet = document.createElement('style'),
$rangeInput = $('.range'),
prefs = ['webkit-slider-runnable-track', 'moz-range-track', 'ms-track'];
document.body.appendChild(sheet);
var getTrackStyle = function (el) {
var curVal = el.value,
style = '';
for (var i = 0; i < prefs.length; i++) {
style += '.range::-' + prefs[i] + '{background: linear-gradient(to right, #34495e 0%, #34495e ' + curVal*20 + '%, #fff ' + curVal + '%, #fff 100%)}';
}
return style;
}
$rangeInput.on('input', function () {
sheet.textContent = getTrackStyle(this);
});
You can use the webkit, firefox and ms track options. However they will only work on compatible browsers.
I would like to make it a bit more obvious that the elements on the page are clickable.
To do this, when the page loads, I would like to loop through them and have the drop shadow show for about a second or so, then revert it to its original state and move on to the next. I only want to loop the elements once.
This is my current attempt, but I'm sure its not threaded right. I think it just delays the load of page. It just attempts to change the css class for the element for 2 seconds, then sets it back.
function animateBarGraph() {
var elements = $(".element");
elements.each(function() {
$(this).css({
'class': 'dropShadowClass'
}).delay(2000);
$(this).css("class", "element");
});
I think you need two parameters here: one is the step (duration between activating two elements) and duration (between start of rise and start of fall on one particular element).
Play with step and duration till you like the result. The actual duration of rise and fall are set in the box-shadow transition (CSS: the .6s).
If you make duration param shorter than the actual CSS duration, it will begin the descend before finishing the rise. Might look weird.
I added the rise/fall effect to hover, too. It seems more natural.
Here's how I'd do it:
$(document).ready(function () {
$custAnim = {
'step': 300,
'duration': 600,
'animateBarGraphElement': function (elem) {
elem.addClass('animated');
setTimeout(function() {
elem.removeClass('animated');
}, $custAnim.duration
);
},
'animateBarGraph': function (i) {
var elements = $(".element");
if (elements.length > i) {
$custAnim.animateBarGraphElement(elements.eq(i));
setTimeout(function () {
$custAnim.animateBarGraph(i + 1);
}, $custAnim.step);
}
}
};
$custAnim.animateBarGraph(0);
});
body {
background-color: #f5f5f5;
}
.container {
position: relative;
width: 100%;
}
button, .element {cursor: pointer;}
.element {
background-color: white;
border-radius: 4px;
width: 60px;
display: inline-block;
height: 60px;
margin: 10px;
padding: 20px;
box-shadow: 0 1px 3px 0 rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 2px 1px -1px rgba(0,0,0,.12);
transition: box-shadow .6s ease;
}
.element.animated, .element:hover {
box-shadow: 0 3px 5px -1px rgba(0,0,0,.2),0 5px 8px 0 rgba(0,0,0,.14),0 1px 14px 0 rgba(0,0,0,.12);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div class="container">
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
<div class="element"></div>
</div>
<button onclick="$custAnim.animateBarGraph(0)">Run again</button>
</body>
delay is the worst choice for that, personally I would play with css animation where you can set how many times it has to perform (1 in this case) and animation delay. But since time is money I crafted something like that on my knee, hope you find it useful:
function addShadow(elm){$(elm).addClass('shadow'); console.log(elm)}
function removeShadow(elm){$(elm).removeClass('shadow')}
$(document).ready(function(){
var elements = $("a, button");
var duration = 1000;
$.each(elements, function(i, elm) {
window.setTimeout(addShadow, i*duration, elm);
window.setTimeout(removeShadow, (i*duration + duration), elm);
});
});
http://jsfiddle.net/dcvbc82x/
Here's a plugin. I used all my imagination inventing a name for it.
$(document).ready(function() {
$('.element').ripple('dropShadowClass', 2000);
});
(function ( $ ) {
$.fn.ripple = function(cssClass, mills) {
var delay = 0;
return this.each(function() {
var $self = $(this);
setTimeout(function() {
$self.addClass(cssClass);
setTimeout(function() {
$self.removeClass(cssClass);
}, mills);
}, delay);
delay += mills;
});
};
}( jQuery ));
.dropShadowClass {
box-shadow: 1px 1px 3px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<html>
<body>
Link
Link
Link
Link
</body>
</html>