Using jQuery to trigger animations on position and size changes with onmouseenter and onmouseleave

After discovering that jQuery's onmouseenter/onmouseleave event is triggered every time the element's position/size changes during animation, I implemented a simple validation with

if (img$.is(':animated')) return false;
at the start of both event handlers.

Unfortunately, this validation led to another issue where the mouseleave event sometimes wouldn't execute because it returned false early while the mouseenter event was still ongoing.

$(function() {

  $("img[data-alt-src]").on('mouseenter', function(e) {
      e.stopPropagation();
      e.preventDefault();
      var img$ = $(e.currentTarget);
      if (img$.is(':animated')) return false; // validation
      img$.finish().animate({
        opacity: '-=1.0',
        deg: '+=90'
      }, {
        duration: 250,
        step: function(now) {
          img$.css({
            '-moz-transform': 'rotateY(' + now + 'deg)',
            '-webkit-transform': 'rotateY(' + now + 'deg)',
            '-o-transform': 'rotateY(' + now + 'deg)',
            '-ms-transform': 'rotateY(' + now + 'deg)',
            transform: 'rotateY(' + now + 'deg)'
          });
        },
        complete: function() {
          img$.data('tmp-src', img$.attr('src'));
          img$.attr('src', img$.data('alt-src'));
        }
      });
      img$.animate({
        opacity: '+=1.0',
        deg: '-=90'
      }, {
        duration: 250,
        step: function(now) {
          img$.css({
            '-moz-transform': 'rotateY(' + now + 'deg)',
            '-webkit-transform': 'rotateY(' + now + 'deg)',
            '-o-transform': 'rotateY(' + now + 'deg)',
            '-ms-transform': 'rotateY(' + now + 'deg)',
            transform: 'rotateY(' + now + 'deg)'
          });
        }
      });
    })
    .on('mouseleave', function(e) {
      e.stopPropagation();
      e.preventDefault();
      var img$ = $(e.currentTarget);
      if (img$.is(':animated')) return false; // the validation
      img$.finish().animate({
        opacity: '-=1.0',
        deg: '+=90'
      }, {
        duration: 250,
        step: function(now) {
          img$.css({
            '-moz-transform': 'rotateY(' + now + 'deg)',
            '-webkit-transform': 'rotateY(' + now + 'deg)',
            '-o-transform': 'rotateY(' + now + 'deg)',
            '-ms-transform': 'rotateY(' + now + 'deg)',
            transform: 'rotateY(' + now + 'deg)'
          });
        },
        complete: function() {
          img$.attr('src', img$.data('tmp-src'));
        }
      });
      img$.animate({
        opacity: '+=1.0',
        deg: '-=90'
      }, {
        duration: 250,
        step: function(now) {
          img$.css({
            '-moz-transform': 'rotateY(' + now + 'deg)',
            '-webkit-transform': 'rotateY(' + now + 'deg)',
            '-o-transform': 'rotateY(' + now + 'deg)',
            '-ms-transform': 'rotateY(' + now + 'deg)',
            transform: 'rotateY(' + now + 'deg)'
          });
        }
      });
    });

});
img {
  width: 150px;
  height: 150px;
  margin-right: 1.5em;
}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>

  <div style="position: relative; display: inline-block">
    <img
      src="http://mcenter.lazim.org/image/cache/catalog/demo/nikon_d300_1-270x270.jpg"
      data-alt-src="http://mcenter.lazim.org/image/cache/catalog/demo/nikon_d300_3-270x270.jpg"
      alt="">
    <img
      src="http://mcenter.lazim.org/image/cache/catalog/demo/nikon_d300_1-270x270.jpg"
      data-alt-src="http://mcenter.lazim.org/image/cache/catalog/demo/nikon_d300_3-270x270.jpg"
      alt="">
    <img
      src="http://mcenter.lazim.org/image/cache/catalog/demo/nikon_d300_1-270x270.jpg"
      data-alt-src="http://mcenter.lazim.org/image/cache/catalog/demo/nikon_d300_3-270x270.jpg"
      alt="">
    <img
      src="http://mcenter.lazim.org/image/cache/catalog/demo/nikon_d300_1-270x270.jpg"
      data-alt-src="http://mcenter.lazim.org/image/cache/catalog/demo/nikon_d300_3-270x270.jpg"
      alt="">
  </div>
  
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
  
</body>
</html>

https://i.sstatic.net/3YuHg.gif

I'm facing a challenge in finding a solution for this issue. Any suggestions?

Answer №1

Hopefully, this modification will work as intended. I have incorporated the setTimout function to switch the image source halfway through the animation duration.

$(function() {
$("img[data-alt-src]").on('mouseenter', function(e) {
e.stopPropagation();
e.preventDefault();
var img$ = $(e.currentTarget);
if (img$.is(':animated')) return false; // ensuring no ongoing animations
img$.finish().animate({
opacity: '-=1.0',
deg: '+=90'
}, {
duration: 250,
step: function(now) {
img$.css({
'-moz-transform': 'rotateY(' + now + 'deg)',
'-webkit-transform': 'rotateY(' + now + 'deg)',
'-o-transform': 'rotateY(' + now + 'deg)',
'-ms-transform': 'rotateY(' + now + 'deg)',
transform: 'rotateY(' + now + 'deg)'
});
}
});
setTimeout(function(){
img$.data('tmp-src', img$.attr('src'));
img$.attr('src', img$.data('alt-src'));
img$.data('alt-src', img$.data('tmp-src'));
}, 125);
img$.animate({
opacity: '+=1.0',
deg: '-=90'
}, {
duration: 250,
step: function(now) {
img$.css({
'-moz-transform': 'rotateY(' + now + 'deg)',
'-webkit-transform': 'rotateY(' + now + 'deg)',
'-o-transform': 'rotateY(' + now + 'deg)',
'-ms-transform': 'rotateY(' + now + 'deg)',
transform: 'rotateY(' + now + 'deg)'
});
}
});
  }).on('mouseleave', function(e) {
e.stopPropagation();
e.preventDefault();
var img$ = $(e.currentTarget);
      if (img$.is(':animated')) return false; // ensuring no ongoing animations
      img$.finish().animate({
      opacity: '-=1.0',
      deg: '+=90'
      }, {
      duration: 250,
      step: function(now) {
      img$.css({
      '-moz-transform': 'rotateY(' + now + 'deg)',
      '-webkit-transform': 'rotateY(' + now + 'deg)',
      '-o-transform': 'rotateY(' + now + 'deg)',
      '-ms-transform': 'rotateY(' + now + 'deg)',
      transform: 'rotateY(' + now + 'deg)'
      });
      }
      });
      setTimeout(function(){
      img$.data('tmp-src', img$.attr('src'));
      img$.attr('src', img$.data('alt-src'));
      img$.data('alt-src', img$.data('tmp-src'));
      }, 125);
      img$.animate({
      opacity: '+=1.0',
      deg: '-=90'
      }, {
      duration: 250,
      step: function(now) {
      img$.css({
      '-moz-transform': 'rotateY(' + now + 'deg)',
      '-webkit-transform': 'rotateY(' + now + 'deg)',
      '-o-transform': 'rotateY(' + now + 'deg)',
      '-ms-transform': 'rotateY(' + now + 'deg)',
      transform: 'rotateY(' + now + 'deg)'
      });
      }
      });
  });
});
img {
  width: 150px;
  height: 150px;
  margin-right: 1.5em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div style="position: relative; display: inline-block">
<img
src="http://mcenter.lazim.org/image/cache/catalog/demo/nikon_d300_1-270x270.jpg"
data-alt-src="http://mcenter.lazim.org/image/cache/catalog/demo/nikon_d300_3-270x270.jpg"
alt="">
<img
src="http://mcenter.lazim.org/image/cache/catalog/demo/nikon_d300_1-270x270.jpg"
data-alt-src="http://mcenter.lazim.org/image/cache/catalog/demo/nikon_d300_3-270x270.jpg"
alt="">
<img
src="http://mcenter.lazim.org/image/cache/catalog/demo/nikon_d300_1-270x270.jpg"
data-alt-src="http://mcenter.lazim.org/image/cache/catalog/demo/nikon_d300_3-270x270.jpg"
alt="">
<img
src="http://mcenter.lazim.org/image/cache/catalog/demo/nikon_d300_1-270x270.jpg"
data-alt-src="http://mcenter.lazim.org/image/cache/catalog/demo/nikon_d300_3-270x270.jpg"
alt="">
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

"Use PHP to open a webpage and navigate to a specific position within the page

Is it possible to open a specific page (id=26) at a set position? On the front page, I am using this PHP code in the file to turn the title into a link to the page: <a href="<?php echo get_page_link(26); ?>"> <?php if(!empty( $clean_bi ...

What is the proper method for overriding styles in material-ui v5 for properties that are not present in the themes components?

Currently, I am customizing MuiDataTables using the adaptv4theme in the following manner: declare module '@material-ui/core/styles/overrides' { export interface ComponentNameToClassKey { MUIDataTable: any; MUIDataTableFilterList: any; ...

Unable to add ngRoute dependency in Angular

I'm facing an issue while trying to set up a basic Angular route in my current project, encountering the error: Uncaught Error: [$injector:modulerr] I have ensured that I have injected ngRoute as a dependency in my module and included the angular-rou ...

What prevents Django websites from being embedded within another HTML (iframe)?

I attempted to include a Django form within another HTML page, but it's not functioning correctly. I've tried on several of my other Django sites with no success. I even tested it on other websites as well. Is there a restriction on using Django ...

What sets apart Angular's $http.post from jQuery's $.post?

What is the difference between Angular's $http.post and jQuery's $.post? $http.post() vs $.post() Does $http.post() internally use $.ajax from jQuery or does it create its own XMLHttpRequest? I am currently experiencing an issue with Angular&a ...

Storing Information in a Two-Dimensional Array using JavaScript

Looking to loop through the Data array and indicate with an "O" if it contains the specified Month and Number. For example, for "Jan-1", Array1[0][0] should be set to "O". However, the code provided below is not working as expected. Any assistance would ...

Ways to eliminate the existing image during an image upload process

When a user decides to change their profile picture, I want the link in the database to be updated and the new image moved to the upload folder. The code should also remove the previous image associated with that specific user from the upload folder. The ...

The functionality of XMLHttpRequest becomes unreliable when dealing with GET parameters

I'm attempting to retrieve the DOM of a specific page. var req = new XMLHttpRequest(); req.open( 'GET', '/sport-hobby-kultura?adListing-visualPaginator-page=2&adListing-url=sport-hobby-kultura&do=adListing-visualPaginator-showP ...

What causes the return of 'undefined' during the execution of type coercion?

Can you explain why the type of a variable changes but the value remains undefined when trying to set it? let average; // Do I need to initialize with 'average = 0;' for it to work properly? for (const [oddName, odd] of Object.entries(game.odd ...

When there is an expensive calculation following a Vue virtual DOM update, the update may not be

Currently, I am facing an issue with adding a loading screen to my app during some heavy data hashing and deciphering processes that take around 2-3 seconds to complete. Interestingly, when I removed the resource-intensive parts, the screen loads immediate ...

Switch the orientation of a live table moving horizontally to vertically and vice versa

config.previewData = [ { Products:27989, Total Customers:294, Metrics:"MVC", Toner Products:5928, INK Products:22061 }, { Products:56511, Total Customers:376, Metrics:"SMB", ...

Adding Bootstrap modal content to a webpage before it renders is a simple process that involves preloading the

When using Bootstrap modal, is it possible to load a remote URL along with the parent page without needing to click on a button? ...

Does anyone know of a convenient tool that can automatically provide suggested street names for mailing addresses in every country across the globe, for free?

Is there a convenient tool that automatically completes street addresses for various countries worldwide? I'm considering options similar to YQL from Yahoo or Foursquare. I'd like to provide users with suggestions of known street names as they ...

Ways to detect events even after the object has been swapped out in JavaScript

I am currently developing a JavaScript-based Scrabble game and encountering a puzzling issue. The problem arises when tiles are generated within a tile rack div using a specific function, and an event listener is set up to respond to clicks on the tile div ...

Unknown CSS element discovered: bootstrap, gradient, carousel

I recently created a random quote app using javascript, jQuery, and bootstrap on Codepen. Everything worked perfectly there. However, when I organized the files, pushed them to git, and tried to view the app from Safari, I encountered some warnings and t ...

Utilizing jQuery arrays to retrieve JSON object properties

Here is the JSON data structure I am working with: { "head": { "heading": ["header1", "header2", "header3"] }, "body": { "elements": [{ "header1": { "value": "value1" }, "header2": { "value": "valu ...

Angular: Implementing ComponentFactoryResolver to dynamically create components and render them within SVG element

I created a component that renders DOM elements inside an svg tag: import { Component, Input } from '@angular/core'; @Component({ selector: 'g[hello]', template: `<svg:text x="50%" y="50%" text-anchor="middle">Hello, {{name} ...

Step-by-step guide on retrieving the button text by utilizing a method call

Currently, I am troubleshooting a demo and I'm puzzled as to why the text of the #add-point button is not displaying. $("#add-point").on("click", function(){ activatePointTool(); }); function activatePointTool() { var tool = $(this).text().toU ...

Setting the input value using downshift in ReactJS can be accomplished by following these steps

Currently, I am in the process of creating an autocomplete input text box using downshiftjs. However, I am facing an issue where I cannot set the input text when one of the autocomplete results is clicked. If you would like to view the sample code that I& ...

An error is being thrown by SetState when included within componentDidmount

I am currently learning React JS and have started working on a small application using it. I'm encountering an issue with the SetState method inside the componentDidMount lifecycle method. The scenario is that I have a parent/home component, which ca ...