gradually Increment the opacity for etch-a-sketch project - javascript

I am trying to apply the gradient effect, for example, if my mouse passes a grid cell it will light at first but the more I move my mouse towards that particular cell it will gradually get lighter. Here is my project https://repl.it/#antgotfan/etch-a-sketch and here is a working example (not mine btw), https://codepen.io/beumsk/pen/dVWPOW (just click on the gradient and will see the effect)
I am trying to use "this" and event.target to solve this problem but it is not working. I also tried to use fadeIn with jQuery but it is not my desired effect.
function incrementOpacity() {
let opacity = 0.1;
$(".cell").hover((event) => {
$(event.target).css({"opacity": `${opacity += 0.1}`,
"backgroundColor": "#f5f5f5"})
});
}
In the function, the opacity will increase forever but will stay white.

The issue is setting let opacity = 0.1; outside of the .hover event. The value should be based off of the cell being hovered, so fetch it inside the event via event.target.style.opacity. Also, make sure it is parsed correctly as a float to allow correct incrementing (parseFloat()):
function incrementOpacity() {
$(".cell").hover((event) => {
let opacity = parseFloat(event.target.style.opacity);
$(event.target).css({"opacity": `${opacity + 0.1}`, "backgroundColor": "#f5f5f5"})
});
}
Here is the updated Repl.it for reference: https://repl.it/repls/GreenDigitalWireframe
Couple of optional changes; added check for maximum opacity. Anything over 1 is redundant. Also consider using mouseenter for function so opacity is only increased when hovered on, and not hovered off:
function incrementOpacity() {
$(".cell").mouseenter((event) => {
let opacity = parseFloat(event.target.style.opacity);
if(opacity <= 0.9){
$(event.target).css({"opacity": `${opacity + 0.1}`, "backgroundColor": "#f5f5f5"})
}
});
}
Edit: For clarification, the reason using let opacity = 0.1 in conjunction with ${opacity += 0.1} doesn't work is that in every instance of .hover, the value opacity was being incremented by 0.1, but never reset. Essentially, after 9 (or 10) iterations, opacity was at a value greater than 1, so each cell was "filled" instantly.
2nd Edit: To prevent issue with assigning multiple handles for the .hover (or .mouseenter) function, add event unbinding before setting:
function incrementOpacity() {
$(".cell").off("mouseenter");
$(".cell").mouseenter((event) => { ... });
}
...
function getRandomColors() {
$(".cell").off("mouseenter");
$(".cell").mouseenter((event) => { ... });
}
Also, make sure the bound event is consistent between the two functions, either .hover or .mouseenter.

Related

html button checkbox onchange event doesn't get triggered on iOS 14 when unticking checkbox

I have a website temporarily running on droneard.de which includes a CSS menu (taken from https://codepen.io/omar_anwari_/pen/WdBgBg). This solution uses an invisible checkbox. Now I trigger a JS-function to change the opacity of my content wrapper to make the text better readable by using the onchange event at my button. In the JS-function I set a variable to the current opacity and use it to set/animate the opacity to 0.6 if it's 1 and to 1 if it's 0.6 .
This works great on all modern browsers, but on Safari on iOS 14.8 and on macOS Big Sur I'm having the problem, that it perfectly loses it's capacity if I tick the checkbox/open the menu, but it doesn't set it back to opacity: 1 when closing the menu / unticking the checkbox. I don't think that the problem is in JavaScript, is it possible that Safari doesn't see the unticking as an "onchange" event?
JavaScript:
function menubackground () {
var opa_city__var_from_home = $('.fadeinobject').css('opacity');
if (opa_city__var_from_home == '0.6') {
$(".fadeinobject").animate({"opacity": "1"}, 230);
}
else {
$(".fadeinobject").animate({"opacity": "0.6"}, 230);
}
}
HTML:
<input type="checkbox" onchange="menubackground()" />
Opacity is stored internally as a floating point number, and this introduces possible errors. So format the number with a single decimal place before comparing.
function menubackground () {
var opa_city__var_from_home = $('.fadeinobject').css('opacity');
if (parseFloat(opa_city__var_from_home).toFixed(1) == '0.6') {
$(".fadeinobject").animate({"opacity": "1"}, 230);
}
else {
$(".fadeinobject").animate({"opacity": "0.6"}, 230);
}
}

jQuery fadeTo calls not functioning as expected when called by scroll()

I've been learning Ruby on Rails and Javascript and trying to learn to animate things as I go.
I have a series of bootstrap cards generated by an Articles controller and shown by an article partial in an index view, where the list of cards (representing posts/messages) proceeds down the page. I want these cards to fade into view as they are scrolled into.
I start the card opacity at 0 with css:
$bg_color: #23282e;
$corner_radius: 5px;
.card {
border-radius: $corner_radius;
opacity: 0;
}
and fade it to 1 with javascript:
function fadeCardsIn() {
const window_top = $(window).scrollTop()
const window_bottom = $(window).scrollTop() + $(window).innerHeight()
console.log(`Viewport: ${window_top} to ${window_bottom}.`)
const cards = $(".card")
let count = 0
cards.each(function() {
count += 1
const card = $(this)
const card_top = card.offset().top;
const card_bottom = card.offset().top + card.outerHeight()
// If our card is in the range of the window viewport.
if ((window_bottom > card_top) && (window_top < card_bottom)) {
card.fadeTo(1000, 1, "swing")
console.log(`Showing card ${count}.`)
} else {
card.fadeTo(1000, 0, "swing")
}
})
}
$(document).ready(fadeCardsIn)
$(window).scroll(fadeCardsIn)
I've taken the bits that should allow things to function without all the rails backend and without the partial, with several cards copied/pasted in the html to simulate what I'm working with in the rendered view:
https://jsfiddle.net/n9kemt3L/5/
On load, the javascript function works as expected with the first few cards in the viewport fading in. However on scroll, based on the console log, the correct cards are "showing" and should be animating/fading in, but they either never fade in, or fade in / fade out very late (sometimes upwards of 30+ seconds later of not scrolling).
I'm assuming calling the fadeTo function multiple times on the same cards by scrolling is causing an issue, possibly calling fadeTo many times before the first fadeTo has even completed, but I'm not sure.
How should I go about beginning to solve this? Any suggestions to nudge me in the right direction are very welcome.
If the fadeTo excess calls are breaking the animations, then I imagine I might need to add some sort of state to know when each card is being animated into/out of, but I don't know where I should start with that if that were the case, as each card is generated by rails and served via pagination, and I'm just iterating over each card on the final rendered with jQuery's each() function.
On another note, I haven't been able to get fadeIn and fadeOut to function at all in this setup, hence me making use of fadeTo instead.
Is there a better way to go about this other than calling this sort of function on scroll?
Edit: I managed to get the functionality I was aiming for by simply removing the else statement.
cards.each(function() {
count += 1
const card = $(this)
const card_top = card.offset().top;
const card_bottom = card.offset().top + card.outerHeight()
// If our card is in the range of the window viewport.
if ((window_bottom > card_top) && (window_top < card_bottom)) {
console.log(`Showing card ${count}.`)
card.fadeTo(500, 1, "swing",function(){console.log(`Loaded card ${count}`)})
But I am still wondering if there's a better way to do this, as this each loop does fire off every single time I scroll.
Definitely feel like you're on the right path.
When I make things fade in from the top, bottom, left or right I usually do not explicitly give them an initial opacity of 0 in their own class.
Rather I create an animation class that has an an initial opacity of 0 and then assign it to them.
Like so...
HTML
<div class='card'>im a card example </div>
CSS
.card {
}
#keyframes fromRight {
0% {
transform: translateX(50px);
opacity: 0;
}
100% {
transform: translateX(0);
opacity: 1;
}
}
Javascript/jQuery
$(document).ready(function() {
$(window).scroll(function() {
let position = $(this).scrollTop();
console.log(position)
// specify your position by inspecting the page
if (position >= 1100) {
$('.card').addClass('fromRight');
}
});
})

Div Transitions - IE vs. others

I have a JSFiddle that displays a series of boxes. If one of the boxes is clicked, it expands to cover the other boxes, then displays text. When the now expanded box is clicked, it retracts to its original width and height. This javascript works flawlessly in Firefox, Chrome, and Safari. However, in Internet Explorer (v10), the box expands but fails to retract. Any Insight on why this may be?
JSFiddle: http://jsfiddle.net/QBdDE/
Javascript:
$('div').on('click', function (e) {
if ($(this).hasClass('clicked')) {
setTimeout(function (div) {
return function () { div.css('z-index', '') ; } ;
} ($(this)), 1000) ;
$('.overlay-text').hide();
}
else {
$(this).css('z-index', 400) ;
setTimeout(function(){$('.overlay-text').show();},1000);
}
$(this).toggleClass('clicked') ;
});
What's Going On
Problem:
pointer-events support was added in IE11. IE10 is ignoring this, and because your overlay is on top, the mouse is interacting with it. We can get around this though!
Solution:
We need to remove dependency on that CSS rule. To do this, we need to do two things:
1.) We need to make the hover color stays applied even if the :hover effect isn't happening. We can add another selector to our CSS so that the .clicked class will cause the colors.
2.) We need to address what happens when .overlay_text is clicked, and use that to trigger the shrinking animation.
Code
1.) Hover Effect
We need to add in another select to every place :hover is used:
Old CSS:
.first_box:hover {
...background color rule ...
}
New CSS:
.first_box:hover, .first_box.clicked {
...background color rule ...
}
Duplicate the above for all 4 box rules.
2.) .overlay-text Trigger
We need to cause a click on .overlay-text to trigger the shrinking.
Old JS:
$('div').on('click', function (e) {
if ($(this).hasClass('clicked')) {
setTimeout(function (div) {
return function () { div.css('z-index', '') ; } ;
} ($(this)), 1000) ;
$('.overlay-text').hide();
}
else {
$(this).css('z-index', 400) ;
setTimeout(function(){$('.overlay-text').show();},1000);
}
$(this).toggleClass('clicked') ;
});
New JS:
We have to add a new selector to the .on() code, then we have to add .clicked to both the selected square, add the overlaying section. Finally we have to remove .clicked from both. We can't use .toggleClass() because we are adding to $(this) and removing from all divs.
$('div, .overlay-text').on('click', function (e) {
if ($(this).hasClass('clicked')) {
setTimeout(function (div) {
return function () { div.css('z-index', '') ; } ;
} ($(this)), 1000) ;
$('.overlay-text').hide();
$('div').removeClass('clicked');
$('.overlay-text').removeClass('clicked');
}
else {
$(this).css('z-index', 400) ;
setTimeout(function(){$('.overlay-text').show();},1000);
$(this).addClass('clicked');
$('.overlay-text').addClass('clicked');
}
});
Summary
I've tested in IE10 and it works.
Working Example:
Extra
If I may say, the CSS structure you are using could be improved and your animations will look a lot better. Chrome and IE both flicker during the animation of the two left blocks.
This is because their width AND position is being animated. If you position them from right:0, only their width will animate and it'll look a lot smoother.
I've created a Fiddle for you to address the above. I used absolute positioning. The CSS ends up being shorter, but mainly the animation doesn't flicker. Take a look:
Working Example:
Extra 2
As per comments from OP, we are going to prevent users from double clicking. Since all animations take 1 second, we will disable clicking from triggering anything for 1 second after each click.
It's actually pretty simple to do. In the Extra 1 above, we cleaned up the JS, and it became this:
$('div, .overlay-text').on('click', function (e) {
if ($(this).hasClass('clicked')) {
$('.overlay-text').hide();
$('div').removeClass('clicked');
$('.overlay-text').removeClass('clicked');
}
else {
setTimeout(function(){$('.overlay-text').show();},1000);
$(this).addClass('clicked');
$('.overlay-text').addClass('clicked');
}
});
We just need to add a global variable that starts true. When once the click happens, set it to false immediately, and after 1 second, set it to true. Then we just check to see if it's true, and don't do anything at all if it's false:
var notdouble = 1;
$('div, .overlay-text').on('click', function (e) {
if (notdouble) {
if ($(this).hasClass('clicked')) {
$('.overlay-text').hide();
$('div').removeClass('clicked');
$('.overlay-text').removeClass('clicked');
}
else {
setTimeout(function(){$('.overlay-text').show();},1000);
$(this).addClass('clicked');
$('.overlay-text').addClass('clicked');
}
notdouble=0;
setTimeout(function(){notdouble=1;},1000);
}
});
Working Example:
Note, this builds from the new structure in the Fiddle version 13, so it won't work exactly with the fixed version of the original structure. The concept can be adapted though.
Not working in IE 9 as the div click event never fires. I think it's covered by the section with class="overlay-text". But I've got a workaround by handling the click event of the section and triggering the div click event
$('section').on('click', function (e) {
$('.overlay-text').hide();
$( "div" ).addClass('clicked') ;
$( "div" ).trigger( "click" );
});

Rotating tiles; how to delay a transition after hover

I'm brand spankin' new to Javascript. Here's what I want to do. I want an array of square tiles covering the window and I want them to flip over when the mouse goes over them. I already have a single tile. See the Jsfiddle below.
http://jsfiddle.net/V7cS8/
I would like it so that the tile will flip over completely to the back side, even if the user doesn't hover for the entire animation length (basically, even if the hover is only very brief, I want it to commit to rotating). I want it to hold its flipped state for some minimum amount time and then return if the user is no longer hovering.
Should I be trying to do this entirely in javascript or still using a lot of CSS?
You don't need JavaScript/jQuery at all. Replace all .flip references in your CSS by :hover: http://jsfiddle.net/V7cS8/1/
For delays, you can use transition-delay: 1s.
Apply transition-delay:1s; (delay 1 second, with vendor prefixes) to the normal selector, and transition-delay:0s to the :hover selector. The result is that the backflip will be delayed for 1 second.
Demo: http://jsfiddle.net/s9xcP/2/
Outcome of comment chain: When existing animations have to be completed first, regardless of the hover state, a JavaScript timeout have to be used:
Demo: http://jsfiddle.net/nY8U8/224/
$(function(){
$('.box').hover(function(){
var $this = $(this);
// If not not-ready, do nothing
// By default, the value is `undefined`, !undefined === true
var not_ready = $this.data('box-hover-not-ready');
if (!not_ready) {
$this.addClass('hover');
} else {
// If bosy, defer hover transition
$this.data('box-hover-hovered', true);
}
}, function() {
var $this = $(this);
$this.removeClass('hover');
// Mark state as "busy"
$this.data('box-hover-not-ready', true);
var timeout = setTimeout(function() {
var hovered = $this.data('box-hover-hovered');
if (hovered) {
// If a hover transition is deferred, activate it now.
$this.addClass('hover');
$this.data('box-hover-hovered', false);
}
// Mark state as "not busy"
$this.data('box-hover-not-ready', false);
}, 2000); /* 2 seconds*/
// Remove previous timeout, set new one.
clearTimeout($this.data('box-hover-timeout'));
$this.data('box-hover-timeout', timeout);
});
});

Use jQuery's switchClass method to fade in an element?

Is this possible? I've tried visibility:hidden/visibility:visible and display:none/display:block on the classes to switch between, but both result in the element popping in at the end.
When styling the two classes, use the opacity property. .swithClass will be able to transition smoothly between varying opacities.
Example:
.FadeFrom {
opacity: 0.0;
}
.FadeTo {
opacity: 1.0;
}
Look here on how to implement JQuery Fading
http://api.jquery.com/category/effects/fading/
You can handle other events in the fade in and out using the call back function like this:
$('.someClass').fadeIn('slow', function() {
// run extra code here
});
$('.someClass').fadeOut('slow', function() {
// run extra code here
});
Use .animate()
$("#myElement").animate({ opacity: 1, left: 0 }, 1000);
To get .switchClass() to work, you'll have to edit the jQuery code. Find function getElementStyles(). In the else, after if (typeof style[key] === 'string') { add this code:
if (key == "filter" && /^alpha\(opacity=(\d+)\)$/.test(style[key])) {
newStyle.opacity = parseFloat(RegExp.$1) / 100;
}
That should do it.

Categories