Top
craft-uikit
craft-widget-

Core/Transition.js


/** 
 * Entry point for animation.
 * 
 * @namespace Craft.Core.Transition
 * @packagename Craft.Core.Transition
 * 
 * @example
 * 
 * Craft.Core.Transition.animate({
 *     element : this.view.getElementById('anim_target');,
 *     properties : {
 *         top  : '100px',
 *         left : '150px',
 *     },
 *     duration : 200,   // number (msec)
 *     ease : 'ease-in',
 *     callback : () => {
 *         console.log('animation ended');
 *     }
 * });
 * 
 */
export var Transition = {
	
	/** @private */
	packagename : 'Craft.Core.Transition',
	
	/**
	 * Make animation
	 * 
	 * @memberof Craft.Core.Transition
	 * @method Craft.Core.Transition.animate
	 * 
	 * @param {Object} options - animation paramaters
	 * @param {Element} options.element - element
	 * @param {Object} options.properties - css key-value: ex) top:'100px'
	 * @param {Number} options.duration - msec
	 * @param {Number} options.delay - msec
	 * @param {String} options.ease - ease-in-out
	 * @param {Function} options.callback - callback
	 */
	animate : function(options){
		new Animator(options).animate();
	}
	
};

/** 
 * Internal animation object
 * @access private
 */
class Animator {
	
	/**
	 * Animation constructor
	 * @param {Object} options - animation paramaters
	 * @param {Element} options.element - element
	 * @param {Object} options.properties - css key-value: ex) top:'100px'
	 * @param {Number} options.duration - msec
	 * @param {Number} options.delay - msec
	 * @param {String} options.ease - ease-in-out
	 * @param {Function} options.callback - callback
	 */
	constructor(options){
		this.packagename = 'Craft.Core.Transition.Animator',
		
		this.DEFAULT_DURATION = 150;
		this.DEFAULT_EASE     = 'ease-in';
		
		this.options = options;
	}
	
	/**
	 * Do animation
	 */
	animate(){
		let element    = this.options.element;
		let properties = this.options.properties || {};
		let duration   = this.options.duration   || this.DEFAULT_DURATION; // Number(msec)
		let delay      = this.options.delay      || 0;
		let ease       = this.options.ease       || this.DEFAULT_EASE;
		let callback   = this.options.callback;
		
		if( !element ){ return; }
		
		let animated = false;
		let transitions = [];
		let keys = Object.keys(properties);
		for( let i=0; i<keys.length; i++ ){
			transitions.push( keys[i] + ' ' + String(duration) + 'ms ' + ease + ' ' + delay + 'ms' );
			if( i === 0 ){
				element.style[keys[i]] = window.getComputedStyle(element).getPropertyValue(keys[i]); // force reflow once
			}
		}
		let transition = transitions.join(', ');
		
		element.style.transition = transition;
		
		let handler = function(event){
			if( animated ){ return; }
			animated = true;
			clearTimeout(no_animation);
			element.removeEventListener('transitionend',handler);
			element.style.transition = '';
			if( callback ){ callback(); }
		};
		element.addEventListener('transitionend',handler);
		let no_animation = setTimeout(handler, (parseInt(duration) + parseInt(delay) + 50) );
		
		keys.map(function(key){
			element.style[key] = properties[key];
		});
	}
	
};