nikitasius
nikitasius

Reputation: 89

Swap images with animation or delay on JS

I've fond a fiddle: http://jsfiddle.net/17g6q8k0/2/

    <img data-alt-src="http://cdn1.iconfinder.com/data/icons/fatcow/32/accept.png"
src="http://cdn1.iconfinder.com/data/icons/fatcow/32/cancel.png" />

and JS part

        var sourceSwap = function () {
            var $this = $(this);
            var newSource = $this.data('alt-src');
            $this.data('alt-src', $this.attr('src'));
            $this.attr('src', newSource);
        }

        $(function() {
            $('img[data-alt-src]').each(function() { 
                new Image().src = $(this).data('alt-src'); 
            }).hover(sourceSwap, sourceSwap); 
        });

When you move mouse on image it's changing. When you remove mouse - it's changing back as it was.

In current example it changes momentally.

How to add pause or animate it (animation better)?

This images have same size. But i'll use it with images which have differ sizes (like [f] and [facebook] buttons on mousehover) and to make it more easy for eyes.

Upvotes: 2

Views: 1757

Answers (2)

serraosays
serraosays

Reputation: 7869

I know what you are trying to do, but don't. Image substitution is a technique from 10-15 years ago. If you want to animate a checkmark to a cancel sign, the best way would be to morph an SVG object. There is a whole library that can do this for you: http://www.transformicons.com/

They even have a check > cancel sign object. The code for just that one object looks like this...

HTML:

<button type="button" class="tcon tcon-remove tcon-remove--check" aria-label="remove item">
  <span class="tcon-visuallyhidden">remove item</span>
</button>

CSS:

.tcon {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  border: none;
  cursor: pointer;
  display: -webkit-flex;
  display: -ms-flexbox;
  display: flex;
  -webkit-justify-content: center;
  -ms-flex-pack: center;
  justify-content: center;
  -webkit-align-items: center;
  -ms-flex-align: center;
  align-items: center;
  height: 40px;
  transition: 0.3s;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  width: 40px;
  background: transparent;
  outline: none;
  -webkit-tap-highlight-color: transparent;
  -webkit-tap-highlight-color: transparent; }
  .tcon > * {
    display: block; }
  .tcon:hover,
  .tcon:focus {
    outline: none; }
  .tcon::-moz-focus-inner {
    border: 0; }

.tcon-remove {
  height: 40px;
  position: relative;
  -webkit-transform: scale(0.75);
  transform: scale(0.75);
  width: 40px; }
  .tcon-remove::before,
  .tcon-remove::after {
    content: "";
    display: block;
    border-radius: 2px;
    width: 85%;
    height: 25%;
    position: absolute;
    top: 37%;
    left: 8%;
    transition: 0.3s;
    background: black; }
  .tcon-remove::before {
    -webkit-transform: rotate(45deg);
    transform: rotate(45deg); }
  .tcon-remove::after {
    -webkit-transform: rotate(-45deg);
    transform: rotate(-45deg); }

.tcon-remove--check.tcon-transform::before {
  -webkit-transform: rotate(-135deg) translate(5%, -10%);
  transform: rotate(-135deg) translate(5%, -10%);
  top: 50%;
  width: 55%; }

.tcon-remove--check.tcon-transform::after {
  -webkit-transform: rotate(-45deg) translate(20%, 10%);
  transform: rotate(-45deg) translate(20%, 10%);
  top: 50%;
  width: 85%; }

.tcon-visuallyhidden {
  border: 0;
  clip: rect(0 0 0 0);
  height: 1px;
  margin: -1px;
  overflow: hidden;
  padding: 0;
  position: absolute;
  width: 1px; }
  .tcon-visuallyhidden:active,
  .tcon-visuallyhidden:focus {
    clip: auto;
    height: auto;
    margin: 0;
    overflow: visible;
    position: static;
    width: auto; }

JS:

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD module
    define(factory);
  } else if (typeof exports === 'object') {
    // CommonJS-like environment (i.e. Node)
    module.exports = factory();
  } else {
    // Browser global
    root.transformicons = factory();
  }
}(this || window, function () {

  // ####################
  // MODULE TRANSFORMICON
  // ####################
  'use strict';

  var
    tcon = {}, // static class
    _transformClass = 'tcon-transform',

    // const
    DEFAULT_EVENTS = {
      transform : ['click'],
      revert : ['click']
    };

  // ##############
  // private methods
  // ##############

  /**
  * Normalize a selector string, a single DOM element or an array of elements into an array of DOM elements.
  * @private
  *
  * @param {(string|element|array)} elements - Selector, DOM element or Array of DOM elements
  * @returns {array} Array of DOM elements
  */
  var getElementList = function (elements) {
    if (typeof elements === 'string') {
      return Array.prototype.slice.call(document.querySelectorAll(elements));
    } else if (typeof elements === 'undefined' || elements instanceof Array) {
      return elements;
    } else {
      return [elements];
    }
  };

  /**
  * Normalize a string with eventnames separated by spaces or an array of eventnames into an array of eventnames.
  * @private
  *
  * @param {(string|array)} elements - String with eventnames separated by spaces or array of eventnames
  * @returns {array} Array of eventnames
  */
  var getEventList = function (events) {
    if (typeof events === 'string') {
      return events.toLowerCase().split(' ');
    } else {
      return events;
    }
  };

  /**
  * Attach or remove transformicon events to one or more elements.
  * @private
  *
  * @param {(string|element|array)} elements - Selector, DOM element or Array of DOM elements to be toggled
  * @param {object} [events] - An Object containing one or more special event definitions
  * @param {boolean} [remove=false] - Defines wether the listeners should be added (default) or removed.
  */
  var setListeners = function (elements, events, remove) {
    var
      method = (remove ? 'remove' : 'add') + 'EventListener',
      elementList = getElementList(elements),
      currentElement = elementList.length,
      eventLists = {};

    // get events or use defaults
    for (var prop in DEFAULT_EVENTS) {
      eventLists[prop] = (events && events[prop]) ? getEventList(events[prop]) : DEFAULT_EVENTS[prop];
    }

    // add or remove all events for all occasions to all elements
    while(currentElement--) {
      for (var occasion in eventLists) {
        var currentEvent = eventLists[occasion].length;
        while(currentEvent--) {
          elementList[currentElement][method](eventLists[occasion][currentEvent], handleEvent);
        }
      }
    }
  };

  /**
  * Event handler for transform events.
  * @private
  *
  * @param {object} event - event object
  */
  var handleEvent = function (event) {
    tcon.toggle(event.currentTarget);
  };

  // ##############
  // public methods
  // ##############

  /**
  * Add transformicon behavior to one or more elements.
  * @public
  *
  * @param {(string|element|array)} elements - Selector, DOM element or Array of DOM elements to be toggled
  * @param {object} [events] - An Object containing one or more special event definitions
  * @param {(string|array)} [events.transform] - One or more events that trigger the transform. Can be an Array or string with events seperated by space.
  * @param {(string|array)} [events.revert] - One or more events that trigger the reversion. Can be an Array or string with events seperated by space.
  * @returns {transformicon} transformicon instance for chaining
  */
  tcon.add = function (elements, events) {
    setListeners(elements, events);
    return tcon;
  };

  /**
  * Remove transformicon behavior from one or more elements.
  * @public
  *
  * @param {(string|element|array)} elements - Selector, DOM element or Array of DOM elements to be toggled
  * @param {object} [events] - An Object containing one or more special event definitions
  * @param {(string|array)} [events.transform] - One or more events that trigger the transform. Can be an Array or string with events seperated by space.
  * @param {(string|array)} [events.revert] - One or more events that trigger the reversion. Can be an Array or string with events seperated by space.
  * @returns {transformicon} transformicon instance for chaining
  */
  tcon.remove = function (elements, events) {
    setListeners(elements, events, true);
    return tcon;
  };

  /**
  * Put one or more elements in the transformed state.
  * @public
  *
  * @param {(string|element|array)} elements - Selector, DOM element or Array of DOM elements to be transformed
  * @returns {transformicon} transformicon instance for chaining
  */
  tcon.transform = function (elements) {
    getElementList(elements).forEach(function(element) {
      element.classList.add(_transformClass);
    });
    return tcon;
  };

  /**
  * Revert one or more elements to the original state.
  * @public
  *
  * @param {(string|element|array)} elements - Selector, DOM element or Array of DOM elements to be reverted
  * @returns {transformicon} transformicon instance for chaining
  */
  tcon.revert = function (elements) {
    getElementList(elements).forEach(function(element) {
      element.classList.remove(_transformClass);
    });
    return tcon;
  };

  /**
  * Toggles one or more elements between transformed and original state.
  * @public
  *
  * @param {(string|element|array)} elements - Selector, DOM element or Array of DOM elements to be toggled
  * @returns {transformicon} transformicon instance for chaining
  */
  tcon.toggle = function (elements) {
    getElementList(elements).forEach(function(element) {
      tcon[element.classList.contains(_transformClass) ? 'revert' : 'transform'](element);
    });
    return tcon;
  };

  return tcon;
}));

Upvotes: 1

MurDaD
MurDaD

Reputation: 362

I've updated your script a bit http://jsfiddle.net/17g6q8k0/182/

You'll need to use css anyway. The first option is to create div with background and animate it.

However, there is another way if you want to use < img>. You have to create container with 2 images.

<div class="hover-image">
  <img src="http://cdn1.iconfinder.com/data/icons/fatcow/32/cancel.png"/>  
  <img class="hover" src="http://cdn1.iconfinder.com/data/icons/fatcow/32/accept.png"/>
</div>

One of it must be positioned absolute and lay over the first image.

.hover-image .hover {
  position: absolute;
  left:0;
  top:0;
  opacity: 0;
}

Than you can animate opacity of these two images.

$this.find("img").each(function(){
  if($(this).hasClass("hover")) {
    $(this).animate({
      'opacity': 1
    }, "slow");
  } else {
    $(this).animate({
      'opacity': 0
    }, "slow")
  }
});

Upvotes: 2

Related Questions