jQuery animation sticking on quick hover - javascript

If you hover over the element slowly, the animation works correctly. The green layer overlaps from the left and then, from the top, the yellow layer overlaps the green layer. This overlapping should undo itself when the mouse leaves the element, starting with undoing the yellow overlap and then the green one.
But if the cursor hovers over it too quickly, the animation gets stuck on the yellow overlap until you re-mousover and then mouseout. I've tried adding .stop(false, true) jQuery method before each of the .animate methods, which is what I read has remedied similar problems but this didn't work. I tried it by chaining it right before the .animate function, I tried just about all variations of this, on all of the functions, and also with .stop(true,true);.
Is there a way I can stop the mouseout portion from firing if the mouseover portion doesn't finish before the cursor leaves the element?
$(document).ready(function() {
$('#con').hover(
function() { // handlerIn
$('#crossX').animate({'width': '115px'}, function() {
$('#crossY').animate({'height': '115px'})
})
},
function() { // handlerOut
$('#crossY').animate({'height': '15px'}, function() {
$('#crossX').animate({'width': '15px'})
})
}
)
});
#con {
position: relative;
display: flex;
justify-content: center;
align-items: center;
width: 130px;
height: 130px;
overflow: hidden;
//background-color: black;
}
#one {
width: 100px;
height: 100px;
background-color: lightgrey;
color:black
}
#crossX {
position: absolute;
top: 15px;
left: 0px;
width: 15px;
height: 100px;
background-color: green;
color: yellow;
}
#crossY {
position: absolute;
top: 0px;
left: 15px;
width: 100px;
height: 15px;
background-color: yellow;
color: white;
}
#black {
position: absolute;
top: 0px;
left: 0px;
width: 100px;
height: 100px;
border: 15px solid black;
z-index: 10;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="con">
<div id="one"></div>
<div id="crossX"></div>
<div id="crossY"></div>
<div id="black"></div>
</div>

With the following solution it is guaranteed that the "mouse leave part" only runs after the "mouse enter part" is fullfilled and (vice versa).
Additionally the script takes care for the case that on quick user action: "enter > leave > enter" the state remains as if the user haven't done the "quick leave". So actually this should do what you want to achieve (I hope so at least).
var mouseEnter = function() {
// console.log('in');
sPosition = 'in';
if ( !mouseEnterIsDone || !mouseLeaveIsDone ) return mouseEnterIsWaiting = true;
mouseEnterIsDone = false;
$('#crossX').animate({'width':'115px'}, function(){
$.when($('#crossY').animate({'height': '115px'})).then(function(){sanitizeAnimation('enter')})
})
},
mouseLeave = function() {
// console.log('out');
sPosition = 'out';
if ( !mouseEnterIsDone || !mouseLeaveIsDone ) return mouseLeaveIsWaiting = true;
mouseLeaveIsDone = false;
$('#crossY').animate({'height':'15px'}, function(){
$.when($('#crossX').animate({'width': '15px'})).then(function(){sanitizeAnimation('leave')})
})
},
sanitizeAnimation = function( sMode ){
if ( 'enter' == sMode )
mouseEnterIsDone = true;
else
mouseLeaveIsDone = true;
if ( 'in' == sPosition ) {
if ( mouseEnterIsWaiting ) {
mouseEnterIsWaiting = false;
mouseEnter();
}
} else {
if ( mouseLeaveIsWaiting ) {
mouseLeaveIsWaiting = false;
mouseLeave();
}
}
},
mouseEnterIsDone = true,
mouseLeaveIsDone = true,
mouseEnterIsWaiting = false,
mouseLeaveIsWaiting = false,
sPosition = 'out';
$(document).ready(function(){
$('#con').hover(mouseEnter, mouseLeave);
});
body {
padding: 5%;
}
#con {
position: relative;
display: flex;
justify-content: center;
align-items: center;
width: 130px;
height: 130px;
overflow: hidden;
//background-color: black;
}
#one {
width: 100px;
height: 100px;
background-color: lightgrey;
color:black
}
#crossX {
position: absolute;
top: 15px;
left: 0px;
width: 15px;
height: 100px;
background-color: green;
color: yellow;
}
#crossY {
position: absolute;
top: 0px;
left: 15px;
width: 100px;
height: 15px;
background-color: yellow;
color: white;
}
#black {
position: absolute;
top: 0px;
left: 0px;
width: 100px;
height: 100px;
border: 15px solid black;
z-index: 10;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="con">
<div id="one"></div>
<div id="crossX"></div>
<div id="crossY"></div>
<div id="black"></div>
</div>
If you need further explanations feel free to leave a comment

$("#con").mouseenter(function() {
$('body').addClass('Hover');
$('#crossX').stop().animate({'width':'115px'},500, function(){
$('#crossY').stop().animate({'height': '115px'},500);
});
});
$("body").mouseenter(function() {
$('body').addClass('Hover');
$('#crossY').stop().animate({'height':'0px'},500,function(){
$('#crossX').stop().animate({'width':'0px'},500);
});
});
#con {
position: relative;
display: flex;
justify-content: center;
align-items: center;
width: 130px;
height: 130px;
overflow: hidden;
//background-color: black;
}
#one {
width: 100px;
height: 100px;
background-color: lightgrey;
color:black
}
#crossX {
position: absolute;
top: 15px;
left: 0px;
width: 15px;
height: 100px;
background-color: green;
color: yellow;
}
#crossY {
position: absolute;
top: 0px;
left: 15px;
width: 100px;
height: 15px;
background-color: yellow;
color: white;
}
#black {
position: absolute;
top: 0px;
left: 0px;
width: 100px;
height: 100px;
border: 15px solid black;
z-index: 10;
}
body{
background-color:#dcdcdc;
height:500px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
<div id="con">
<div id="one"></div>
<div id="crossX"></div>
<div id="crossY"></div>
<div id="black"></div>
</div>
</body>

Related

Variables inside a function

I have a div which acts like a button when I press it. I add classes to change color and the circle inside moves to the right when is clicked. What I would like to do, is to call a function and then change a global variable inside the function and pass it back. I am also testing the code using the document.getElementById("test").innerHTML and the 12th changes to 13th and vise versa successfully. However, the variable flag13th does not change. It always has a false value.
Any ideas folks on this? I would appreciate your help. Thank you.
document.getElementById("toggleButton").addEventListener("click", dekatosTritos);
var flag13th = false;
function dekatosTritos() {
var ThirteenthSalary = document.getElementById("toggleButton").classList;
if ((ThirteenthSalary.contains("toggle-btn")) && (ThirteenthSalary.contains("active"))) {
flag13th = false;
document.getElementById("test").innerHTML = "12th";
} else {
flag13th = true;
document.getElementById("test").innerHTML = "13th";
}
}
document.getElementById("test11").innerHTML = flag13th;
.toggle-btn {
display: inline-block;
position: relative;
top: 8px;
width: 60px;
height: 28px;
background: gray;
border-radius: 30px;
}
.toggle-btn .inner-circle {
position: absolute;
left: 4px;
top: 4px;
width: 20px;
height: 20px;
background: #fff;
border-radius: 80%;
}
.toggle-btn.active {
background: #4F94CD;
}
.toggle-btn.active>.inner-circle {
margin-left: 32px;
}
<div class="Question_13th">13th Month Salary</div>
<div id="toggleButton" class="toggle-btn">
<div class="inner-circle"></div>
</div>
<p id="test">12th</p>
<p id="test11"> </p>
Here's an example that uses no JavaScript, but rather an input type checkbox that can be submitted with your form:
.toggler {
position: absolute;
overflow: hidden;
width: 1px;
height: 1px;
margin: -1px;
clip: rect(0 0 0 0);
opacity: 0;
}
.toggler-btn {
display: inline-block;
position: relative;
width: 60px;
height: 28px;
border-radius: 28px;
cursor: pointer;
background: gray;
transition: background 0.3s;
}
.toggler-btn:after {
content: "";
position: absolute;
left: 4px;
top: 4px;
width: 20px;
height: 20px;
background: #fff;
border-radius: 100%;
transition: transform 0.3s;
}
.toggler-label::after {
content: attr(data-label);
}
/* CHECKED STATES */
.toggler:checked ~ .toggler-btn {
background: #0bf;
}
.toggler:checked ~ .toggler-btn:after {
transform: translateX(30px);
}
.toggler:checked ~ .toggler-label::after {
content: attr(data-labelchecked);
}
<div class="Question_13th">13th Month Salary?</div>
<input class="toggler" type="checkbox" id="13th" name="13th">
<label class="toggler-btn" for="13th"></label>
<div class="toggler-label" data-label="12th" data-labelchecked="13th"></div>
Here's an example that uses JavaScript, classList.toggle() and bool = !bool to toggle a boolean
const EL_btn = document.querySelector("#toggleButton");
const EL_test = document.querySelector("#test");
let is13 = false;
function dekatosTritos() {
is13 = !is13; // Toggle boolean
EL_btn.classList.toggle('active', is13);
EL_test.innerHTML = is13 ? "13th" : "12th";
}
EL_btn.addEventListener("click", dekatosTritos); // Do on btn click
dekatosTritos(); // and on init.
.toggle-btn {
display: inline-block;
position: relative;
top: 8px;
width: 60px;
height: 28px;
background: gray;
border-radius: 30px;
}
.toggle-btn.active {
background: #4F94CD;
}
.toggle-btn .inner-circle {
position: absolute;
left: 4px;
top: 4px;
width: 20px;
height: 20px;
background: #fff;
border-radius: 80%;
}
.toggle-btn.active>.inner-circle {
margin-left: 32px;
}
<div class="Question_13th">13th Month Salary</div>
<div id="toggleButton" class="toggle-btn">
<div class="inner-circle"></div>
</div>
<p id="test"></p>

Scrollbar handles not visible

The scroll-bar handles aren't visible in my page. I've tried setting overflow-x to auto and scroll for both the #cust1 and #cust2 div's.
I also need five div's to have their horizontal scrolling controlled from just one scroll-bar at the bottom of the page. (Div's #one, #two, #three, #four and #custTimeline)I don't want scroll-bars for each customer div.
Please help. https://jsfiddle.net/c71ytuxz/1/
var c = document.getElementById("custTimeline");
var ctx = c.getContext("2d");
ctx.font = "20px Georgia";
ctx.save();
ctx.rotate(-90*Math.PI/180);
var baseLoc = 130;
var hours = ["5AM","6AM", "7AM","8AM","9AM","10AM","11AM","12 NOON","1PM","2PM","3PM","4PM","5PM","6PM", "7PM", "8PM", "9PM", "10PM", "11PM", "12PM"];
for(i = 0; i < hours.length; i++) {
if (i == 0) {
ctx.fillText(hours[i], -120, baseLoc);
}
else {
baseLoc += 90;
ctx.fillText(hours[i], -120, baseLoc);
}
}
ctx.restore();
#header {
position: fixed;
top: 0px;
left: 0px;
width: 100%;
height: 100px;
background: lightgrey;
}
#cust1 {
position: fixed;
left: 0px;
top: 160px;
width: 1500px;
height: 150px;
background: lightgrey;
overflow-x: scroll;
overflow-y: hidden;
margin-bottom: 10px;
}
#one {
width: 8%;
height: 150px;
background: darkgrey;
float: left;
text-align: center;
}
#two {
margin-left: 25%;
width: 35px;
height: 150px;
background: green;
}
#cust2 {
position: fixed;
top: 320px;
left: 0px;
width: 1500px;
height: 150px;
background: lightgrey;
overflow-x: scroll;
overflow-y: hidden;
}
#three {
width: 8%;
height: 150px;
background: darkgrey;
float: left;
text-align: center;
}
#four {
margin-left: 15%;
width: 35px;
height: 150px;
background: green;
}
<canvas id="custTimeline"
width = "1900"
height = "130"
style = "border:3px solid #aaaaaa;">
</canvas>
<div id="cust1">
<div id="one"><p>
Customer 1
</p></div>
<div id="two"></div>
</div>
<div id="cust2">
<div id="three"><p>
Customer 2
</p></div>
<div id="four"></div>
</div>
Since the #cust1 has a width of 1500px, the scroll will only appear when its content gets wider than that, and at the moment it is only 8% (#one) + 25% + 35px (#two) in total.
If you want it to scroll, change this
#cust1 {
position: fixed;
left: 0px;
top: 160px;
width: 100vw; /* changed property */
height: 150px;
background: lightgrey;
overflow-x: scroll;
overflow-y: hidden;
margin-bottom: 10px;
}
#two {
margin-left: 25%;
width: 1000px; /* changed property */
height: 150px;
background: green;
}
Updated fiddle
Updated based on a comment
To have one scroll update another, here is one way, using jQuery.
$(document).ready(function(){
$( window ).scroll(function(){
var position = $( this ).scrollLeft();
$("#first").scrollLeft(position);
$("#second").scrollLeft(position);
});
});

Mouseover Mouseout with overlapping content

When I mouseover the div with class=background (the little green square in the demo) I fade in the div with class=hover (displaying the grey and blue divs in the demo).
The grey partially overlaps the .background and I can move the mouse around inside it without triggering the mouseout on .background.
But..
If I move the mouse outside the grey div (to hover over the blue for example) then the mouseout on .background gets triggered.
How can I prevent this from happening so that as long as I am hovering over the newly displayed .hover div the mouseout on '.background' will not be triggered?
$('.AddDiv').on('click', function() {
var html = '<div class="container"><div class="background"></div><div class="hover"></div></div>';
$('.Wrap').prepend(html);
});
$(".Wrap").on("mouseover", ".background", function() {
$(this).next(".hover").fadeIn(500);
});
$(".Wrap").on("mouseout", ".hover", function() {
$(this).fadeOut(200);
});
.Wrap {
width: 650px;
height: 800px;
}
.container {
position: relative;
top: 5px;
left: 5px;
width: 200px;
height: 200px;
background-color: red;
float: left;
margin-left: 5px;
margin-top: 5px;
}
.AddDiv {
position: absolute;
top: 0px;
}
.background {
width: 20px;
height: 20px;
background-color: green;
position: absolute;
left: 170px;
top: 10px;
}
.content {
width: 170px;
height: 120px;
background-color: grey;
position: relative;
left: 15px;
top: 15px;
}
.navigation {
width: 190px;
height: 40px;
background-color: blue;
position: relative;
top: 30px;
left: 5px;
}
.hover {
width: 200px;
height: 200px;
background-color: rgba(255, 255, 255, 0.8);
position: absolute;
z-index: 1001;
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="Wrap">
<div class="container">
<div class="background"></div>
<div class="hover">
<div class="content"></div>
<div class="navigation"></div>
</div>
</div>
</div>
<button class=AddDiv>AddDiv</button>
Use mouseleave instead of mouseout:
$('.AddDiv').on('click', function() {
$('.Wrap').prepend($('<div class="container"><div class="background"></div><div class="hover"></div></div>'));
});
$(".Wrap").on("mouseover", ".background", function () {
$(this).next(".hover").fadeIn(500);
});
$(".Wrap").on("mouseleave", ".hover", function () {
$(this).fadeOut(200);
});

How to catch event on a parent div?

I would like to ask:
How to make the group displays OVER the divs a and b?
I want to catch event mousedown on group even if a user click on a div a or b.
Basically the group should visually cover the two other divs, so when I click inside the are covered by the group, only group div should detect mousedown.
Notes: I cannot change HTML structure.
document.getElementById('group').addEventListener('click', function(event) {
event.stopPropagation();
alert('click on: ' + event.target.id);
});
#group {
position: absolute;
width: 250px;
height: 250px;
background-color: yellow;
z-index: 2;
opacity: 0.5;
}
#a {
position: absolute;
left: 80px;
width: 50px;
height: 50px;
margin: 10px;
background-color: blue;
z-index: 0;
}
#b {
position: absolute;
width: 50px;
height: 50px;
margin: 10px;
background-color: blue;
z-index: 0;
}
<div id="group">
<div id="a">A</div>
<div id="b">B</div>
</div>
Use opacity 0 for the children.
Use event.currentTarget instead of event.target.
With this config children are actually above groups, but are not visible and events are caught by groups elem, not children.
document.getElementById('group').addEventListener('click', function(event) {
event.stopPropagation();
alert('click on: ' + event.currentTarget.id);
});
#group {
position: relative;
width: 250px;
height: 250px;
background-color: yellow;
z-index: 2;
opacity: 0.5;
}
#a {
position: relative;
left: 80px;
width: 50px;
height: 50px;
margin: 10px;
background-color: blue;
z-index: 0;
opacity: 0
}
#b {
position: relative;
width: 50px;
height: 50px;
margin: 10px;
background-color: blue;
z-index: 0;
opacity: 0;
}
<div id="group">
<div id="a">A</div>
<div id="b">B</div>
</div>

Menu error caused by HTML or JS?

Im trying to get the menu to be horizontal and then the flags to be shown below the menu when you press the flag-name.
When doing changes to the menu in my code, which of my files should I be editing?
The flags location is correct right now, but the menu is missplaced.
What can be done to get the menu to be horizontal instead of a list?
JSFiddle: http://jsfiddle.net/528k9z8m/
HTML:
<body>
<h1>Kmom03 sandboxen</h1>
<div id="content">
<div id="menu">
<ul>
<li> Elfenbenskusten
<div id="flag-elfenbenskusten"></div>
</li>
<li> Sverige
<div id="flag-sverige"></div>
</li>
<li> Maruritius
<div id="flag-maruritius"></div>
</li>
<li> Japan
<div id="flag-japan"></div>
</li>
</ul>
</div>
</div>
<script type="text/javascript" src="js/main.js"></script>
CSS
body {
}
h1 {
text-align: center;
}
h3 {
color: green;
}
#menu {
width: 500px;
height: 50px;
border: 1px solid black;
}
#content {
border: 1px solid black;
background-color: #eee;
padding: 4em;
margin: 0 auto;
height: 800px;
width: 800px;
border-radius: 30px;
}
.flagga1 {
position: relative;
width: 800px;
height: 500px;
}
.sverige {
background-color: #FECC00;
}
.sverige .box1 {
position: absolute;
width: 250px;
height: 200px;
background-color: #006AA7;
}
.sverige .box2 {
position: absolute;
bottom: 0;
left: 0;
width: 250px;
height: 200px;
background-color: #006AA7;
}
.sverige .box3 {
position: absolute;
top: 0;
right: 0;
width: 425px;
height: 200px;
background-color: #006AA7;
}
.sverige .box4 {
position: absolute;
bottom: 0;
right: 0;
width: 425px;
height: 200px;
background-color: #006AA7;
}
.flag {
position: relative;
width: 300px;
height: 200px;
}
.elfenbenskusten {
background-color: #fff;
}
.elfenbenskusten .part1 {
width: 100px;
height: 200px;
background-color: #F77F00;
}
.elfenbenskusten .part2 {
position: absolute;
top: 0;
left: 200px;
width: 100px;
height: 200px;
background-color: #009e60;
}
.flagga2 {
position: relative;
width: 300px;
height: 200px;
}
.maruritius {
background-color: #EEE;
}
.maruritius .box1 {
position: absolute;
top: 0;
width: 300px;
height: 50px;
background-color: #EA2839;
}
.maruritius .box2 {
position: absolute;
top: 50px;
left: 0;
width: 300px;
height: 50px;
background-color: #1A206D;
}
.maruritius .box3 {
position: absolute;
top: 100px;
width: 300px;
height: 50px;
background-color: #FFD500;
}
.maruritius .box4 {
position: absolute;
bottom: 0;
right: 0;
width: 300px;
height: 50px;
background-color: #00A551;
}
.maruritius .box5 {
position: absolute;
bottom: 0;
right: 0;
background-color: #006AA7;
}
.flagga3 {
position: relative;
height: 200px;
width: 300px;
border-style: solid;
border-width: 1px;
border-color: black;
}
.japan .box1 {
background-color: #FFFFFF;
}
.japan .cirkel1 {
border-radius: 50%;
position: absolute;
top: 40px;
left: 90px;
width: 125px;
height: 125px;
background-color: #BC002D;
}
JS:
(function () {
'use strict';
//var myContent = document.getElementById('content');
//elfenbenskusten
var flagTarget = document.getElementById('flag-elfenbenskusten');
var flagLink = document.getElementById('draw-elfenbenskusten');
function drawFlagElfenbenskusten() {
var flagElfenbenskusten = '<div class="flag elfenbenskusten"><div class="part1"></div><div class="part2"></div></div>'
flagTarget.innerHTML = flagElfenbenskusten;
}
flagLink.addEventListener("click", function () {
console.log("event for clicking link elfenbenskusten.")
drawFlagElfenbenskusten();
});
//sverige
var flagTargetSverige = document.getElementById('flag-sverige');
var flagLinkSverige = document.getElementById('draw-sverige');
function drawFlagSverige() {
var flagSverige = '<div class="flagga1 sverige"><div class="box1"></div><div class="box2"></div><div class="box3"></div><div class="box4"></div></div>'
flagTarget.innerHTML = flagSverige;
}
flagLinkSverige.addEventListener("click", function () {
console.log("event for clicking link elfenbenskusten.")
drawFlagSverige();
});
//maruritius
var flagTargetMaruritius = document.getElementById('flag-maruritius');
var flagLinkMaruritius = document.getElementById('draw-maruritius');
function drawFlagMaruritius() {
var flagMaruritius = '<div class="flagga2 maruritius"><div class="box1"></div><div class="box2"></div><div class="box3"></div><div class="box4"></div><div class="box5"></div></div>'
flagTarget.innerHTML = flagMaruritius;
}
flagLinkMaruritius.addEventListener("click", function () {
console.log("event for clicking link elfenbenskusten.")
drawFlagMaruritius();
});
//japan
var flagTargetJapan = document.getElementById('flag-japan');
var flagLinkJapan = document.getElementById('draw-japan');
function drawFlagJapan() {
var flagJapan = '<div class="flagga3 japan"><div class="box1"></div><div class="cirkel1"></div></div>'
flagTarget.innerHTML = flagJapan;
}
flagLinkJapan.addEventListener("click", function () {
console.log("event for clicking link elfenbenskusten.")
drawFlagJapan();
});
})();
#menu li {
list-style-type: none;
float: left;
margin-right: 10px;
position: relative;
}
#menu ul li>div {
position: absolute;
top: 20px;
}
Fiddle
Guess it's what you want to achieve
you have to edit the css, try this:
ul {
float: left;
width: 100%;
}
a {
float: left;
width: 6em;
text-decoration: none;
padding: 0.2em 0.6em;
}
li {
display: inline;
}

Categories