Reputation: 21
I've come up with this simple code, but for some reason, it does not always work exactly the way I would like it to.
Here's what I have. There are tiles that flip on hover. There are two possible scenarios and two reactions.
If I mouse is hovered over a tile, the tile is supposed to flip 180° and stay in this possition. This happens, if mouseleave happens in longer time than 1 second. After unhover, the tile should flip back to its original state.
If mouse is hovered over a tile and unhover immediately, the tile is supposed to do a full 180° flip before returning to its original state. This happens when mouse leaves in the 1 second timeframe. In this case, the JS scripts waits for the CSS transition to end before fliping the tile back.
Now, this works fine until the second scenario takes place. Then for some reason, the tile returns to its original state after a full transition despite the mouse not leaving the tile. Why is that? Any ideas on how to overcome this issue?
Thanks.
$(function() {
var timeoutId;
$(".tile").mouseenter(function() {
$(this).addClass("flip");
if (!timeoutId) {
timeoutId = window.setTimeout(function() {
timeoutId = null;}, 1000);
}
});
$(".tile").mouseleave(function() {
if (timeoutId) {
$(this).on('transitionend webkitTransitionEnd oTransitionEnd', function () {
$(this).removeClass("flip");
window.clearTimeout(timeoutId);
timeoutId = null;
});
}
else {
$(this).removeClass("flip");
}
});
})
body {
text-align: center;
background-color: #FFFFFF;
color: #454545;
}
.flex-container {
padding: 0;
margin: 0;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row;
justify-content: space-around;
}
.tile {
background: #454545;
margin: 0px;
font-weight: bold;
flex: 1 0 auto;
height: auto;
border: 1px solid #454545;
border-radius: 10%;
}
.tile:before {
content: '';
float: left;
padding-top: 100%;
}
.tile-inner {
position: relative;
width: 100%;
height: 100%;
border-radius: 10%;
transform-style: preserve-3d;
transition: transform 4s;
}
.tile.flip .tile-inner {
transform: rotate3d(-1, 1, 0, 180deg);
transition: transform 1s;
}
.tile-front, .tile-off, .tile-semi, .tile-rsemi, .tile-on {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
border-radius: 10%;
}
.tile-front {
background-color: #1c1c1c;
background-size: 100%;
}
.tile-off {
background-color: #252525;
transform: rotate3d(-1, 1, 0, 180deg);
}
.tile-semi {
background: linear-gradient(to right bottom, #252525 50%, #dedede 50%);
transform: rotate3d(-1, 1, 0, 180deg);
}
.tile-rsemi {
background: linear-gradient(to right bottom, #dedede 50%, #252525 50%);
transform: rotate3d(-1, 1, 0, 180deg);
}
.tile-on {
background-color: #dedede;
transform: rotate3d(-1, 1, 0, 180deg);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<body>
<div class="flex-container">
<div class="tile">
<div class="tile-inner">
<div class="tile-front"></div>
<div class="tile-semi"></div>
</div>
</div>
<div class="tile">
<div class="tile-inner">
<div class="tile-front"></div>
<div class="tile-on"></div>
</div>
</div>
<div class="tile">
<div class="tile-inner">
<div class="tile-front"></div>
<div class="tile-rsemi"></div>
</div>
</div>
</div>
</body>
Upvotes: 2
Views: 56
Reputation: 207501
You are sharing one variable and using it on all of the other tiles. So the timeout for tile 1 will also be with tile 2 when you mouseover it. You should be setting the timeouts for each one individually. Basic idea with data.
$(function() {
$(".tile").mouseenter(function() {
var elem = $(this);
elem.addClass("flip");
if (!elem.data('timeoutId')) {
var tid = window.setTimeout(function() {
elem.removeData('timeoutId')
}, 1000);
elem.data('timeoutId', tid)
}
});
$(".tile").mouseleave(function() {
var elem = $(this);
var timeoutId = elem.data('timeoutId')
if (timeoutId) {
window.clearTimeout(timeoutId);
elem.removeData('timeoutId')
elem.off('transitionend webkitTransitionEnd oTransitionEnd')
elem.on('transitionend webkitTransitionEnd oTransitionEnd', function() {
elem.removeClass("flip");
});
} else {
$(this).removeClass("flip");
}
});
})
body {
text-align: center;
background-color: #FFFFFF;
color: #454545;
}
.flex-container {
padding: 0;
margin: 0;
display: -webkit-box;
display: -moz-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-flex-flow: row;
justify-content: space-around;
}
.tile {
background: #454545;
margin: 0px;
font-weight: bold;
flex: 1 0 auto;
height: auto;
border: 1px solid #454545;
border-radius: 10%;
}
.tile:before {
content: '';
float: left;
padding-top: 100%;
}
.tile-inner {
position: relative;
width: 100%;
height: 100%;
border-radius: 10%;
transform-style: preserve-3d;
transition: transform 4s;
}
.tile.flip .tile-inner {
transform: rotate3d(-1, 1, 0, 180deg);
transition: transform 1s;
}
.tile-front,
.tile-off,
.tile-semi,
.tile-rsemi,
.tile-on {
position: absolute;
width: 100%;
height: 100%;
backface-visibility: hidden;
border-radius: 10%;
}
.tile-front {
background-color: #1c1c1c;
background-size: 100%;
}
.tile-off {
background-color: #252525;
transform: rotate3d(-1, 1, 0, 180deg);
}
.tile-semi {
background: linear-gradient(to right bottom, #252525 50%, #dedede 50%);
transform: rotate3d(-1, 1, 0, 180deg);
}
.tile-rsemi {
background: linear-gradient(to right bottom, #dedede 50%, #252525 50%);
transform: rotate3d(-1, 1, 0, 180deg);
}
.tile-on {
background-color: #dedede;
transform: rotate3d(-1, 1, 0, 180deg);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<body>
<div class="flex-container">
<div class="tile">
<div class="tile-inner">
<div class="tile-front"></div>
<div class="tile-semi"></div>
</div>
</div>
<div class="tile">
<div class="tile-inner">
<div class="tile-front"></div>
<div class="tile-on"></div>
</div>
</div>
<div class="tile">
<div class="tile-inner">
<div class="tile-front"></div>
<div class="tile-rsemi"></div>
</div>
</div>
</div>
</body>
Upvotes: 1
Reputation: 8814
The problem is that when you run:
if (timeoutId) {
$(this).on('transitionend webkitTransitionEnd oTransitionEnd', function () {
$(this).removeClass("flip");
window.clearTimeout(timeoutId);
timeoutId = null;
});
}
The event stays in the element indefinitely. So, next time you hover the element, when it finishes transition, this event triggers again.
What you probably want is to run the event only once
:
if (timeoutId) {
$(this).once('transitionend webkitTransitionEnd oTransitionEnd', function () {
$(this).removeClass("flip");
window.clearTimeout(timeoutId);
timeoutId = null;
});
}
Upvotes: 0