| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706 |
- /**
- * DevExtreme (animation/fx.js)
- * Version: 19.1.16
- * Build date: Tue Oct 18 2022
- *
- * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED
- * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
- */
- "use strict";
- function _typeof(obj) {
- "@babel/helpers - typeof";
- return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(obj) {
- return typeof obj
- } : function(obj) {
- return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj
- }, _typeof(obj)
- }
- var $ = require("../core/renderer");
- var window = require("../core/utils/window").getWindow();
- var eventsEngine = require("../events/core/events_engine");
- var errors = require("../core/errors");
- var getPublicElement = require("../core/utils/dom").getPublicElement;
- var extend = require("../core/utils/extend").extend;
- var typeUtils = require("../core/utils/type");
- var iteratorUtils = require("../core/utils/iterator");
- var translator = require("./translator");
- var easing = require("./easing");
- var animationFrame = require("./frame");
- var support = require("../core/utils/support");
- var positionUtils = require("./position");
- var removeEvent = require("../core/remove_event");
- var eventUtils = require("../events/utils");
- var deferredUtils = require("../core/utils/deferred");
- var when = deferredUtils.when;
- var Deferred = deferredUtils.Deferred;
- var removeEventName = eventUtils.addNamespace(removeEvent, "dxFX");
- var isFunction = typeUtils.isFunction;
- var isPlainObject = typeUtils.isPlainObject;
- var noop = require("../core/utils/common").noop;
- var RELATIVE_VALUE_REGEX = /^([+-])=(.*)/i;
- var ANIM_DATA_KEY = "dxAnimData";
- var ANIM_QUEUE_KEY = "dxAnimQueue";
- var TRANSFORM_PROP = "transform";
- var TransitionAnimationStrategy = {
- initAnimation: function($element, config) {
- $element.css({
- transitionProperty: "none"
- });
- if ("string" === typeof config.from) {
- $element.addClass(config.from)
- } else {
- setProps($element, config.from)
- }
- var that = this;
- var deferred = new Deferred;
- var cleanupWhen = config.cleanupWhen;
- config.transitionAnimation = {
- deferred: deferred,
- finish: function() {
- that._finishTransition($element);
- if (cleanupWhen) {
- when(deferred, cleanupWhen).always(function() {
- that._cleanup($element, config)
- })
- } else {
- that._cleanup($element, config)
- }
- deferred.resolveWith($element, [config, $element])
- }
- };
- this._completeAnimationCallback($element, config).done(function() {
- config.transitionAnimation.finish()
- }).fail(function() {
- deferred.rejectWith($element, [config, $element])
- });
- if (!config.duration) {
- config.transitionAnimation.finish()
- }
- $element.css("transform")
- },
- animate: function($element, config) {
- this._startAnimation($element, config);
- return config.transitionAnimation.deferred.promise()
- },
- _completeAnimationCallback: function($element, config) {
- var that = this;
- var startTime = Date.now() + config.delay;
- var deferred = new Deferred;
- var transitionEndFired = new Deferred;
- var simulatedTransitionEndFired = new Deferred;
- var simulatedEndEventTimer;
- var transitionEndEventName = support.transitionEndEventName() + ".dxFX";
- config.transitionAnimation.cleanup = function() {
- clearTimeout(simulatedEndEventTimer);
- clearTimeout(waitForJSCompleteTimer);
- eventsEngine.off($element, transitionEndEventName);
- eventsEngine.off($element, removeEventName)
- };
- eventsEngine.one($element, transitionEndEventName, function() {
- if (Date.now() - startTime >= config.duration) {
- transitionEndFired.reject()
- }
- });
- eventsEngine.off($element, removeEventName);
- eventsEngine.on($element, removeEventName, function() {
- that.stop($element, config);
- deferred.reject()
- });
- var waitForJSCompleteTimer = setTimeout(function() {
- simulatedEndEventTimer = setTimeout(function() {
- simulatedTransitionEndFired.reject()
- }, config.duration + config.delay + fx._simulatedTransitionEndDelay);
- when(transitionEndFired, simulatedTransitionEndFired).fail(function() {
- deferred.resolve()
- }.bind(this))
- });
- return deferred.promise()
- },
- _startAnimation: function($element, config) {
- $element.css({
- transitionProperty: "all",
- transitionDelay: config.delay + "ms",
- transitionDuration: config.duration + "ms",
- transitionTimingFunction: config.easing
- });
- if ("string" === typeof config.to) {
- $element[0].className += " " + config.to
- } else {
- if (config.to) {
- setProps($element, config.to)
- }
- }
- },
- _finishTransition: function($element) {
- $element.css("transition", "none")
- },
- _cleanup: function($element, config) {
- config.transitionAnimation.cleanup();
- if ("string" === typeof config.from) {
- $element.removeClass(config.from);
- $element.removeClass(config.to)
- }
- },
- stop: function($element, config, jumpToEnd) {
- if (!config) {
- return
- }
- if (jumpToEnd) {
- config.transitionAnimation.finish()
- } else {
- if (isPlainObject(config.to)) {
- iteratorUtils.each(config.to, function(key) {
- $element.css(key, $element.css(key))
- })
- }
- this._finishTransition($element);
- this._cleanup($element, config)
- }
- }
- };
- var FrameAnimationStrategy = {
- initAnimation: function($element, config) {
- setProps($element, config.from)
- },
- animate: function($element, config) {
- var deferred = new Deferred;
- var that = this;
- if (!config) {
- return deferred.reject().promise()
- }
- iteratorUtils.each(config.to, function(prop) {
- if (void 0 === config.from[prop]) {
- config.from[prop] = that._normalizeValue($element.css(prop))
- }
- });
- if (config.to[TRANSFORM_PROP]) {
- config.from[TRANSFORM_PROP] = that._parseTransform(config.from[TRANSFORM_PROP]);
- config.to[TRANSFORM_PROP] = that._parseTransform(config.to[TRANSFORM_PROP])
- }
- config.frameAnimation = {
- to: config.to,
- from: config.from,
- currentValue: config.from,
- easing: easing.convertTransitionTimingFuncToEasing(config.easing),
- duration: config.duration,
- startTime: (new Date).valueOf(),
- finish: function() {
- this.currentValue = this.to;
- this.draw();
- animationFrame.cancelAnimationFrame(config.frameAnimation.animationFrameId);
- deferred.resolve()
- },
- draw: function() {
- if (config.draw) {
- config.draw(this.currentValue);
- return
- }
- var currentValue = extend({}, this.currentValue);
- if (currentValue[TRANSFORM_PROP]) {
- currentValue[TRANSFORM_PROP] = iteratorUtils.map(currentValue[TRANSFORM_PROP], function(value, prop) {
- if ("translate" === prop) {
- return translator.getTranslateCss(value)
- } else {
- if ("scale" === prop) {
- return "scale(" + value + ")"
- } else {
- if ("rotate" === prop.substr(0, prop.length - 1)) {
- return prop + "(" + value + "deg)"
- }
- }
- }
- }).join(" ")
- }
- $element.css(currentValue)
- }
- };
- if (config.delay) {
- config.frameAnimation.startTime += config.delay;
- config.frameAnimation.delayTimeout = setTimeout(function() {
- that._startAnimation($element, config)
- }, config.delay)
- } else {
- that._startAnimation($element, config)
- }
- return deferred.promise()
- },
- _startAnimation: function($element, config) {
- eventsEngine.off($element, removeEventName);
- eventsEngine.on($element, removeEventName, function() {
- if (config.frameAnimation) {
- animationFrame.cancelAnimationFrame(config.frameAnimation.animationFrameId)
- }
- });
- this._animationStep($element, config)
- },
- _parseTransform: function(transformString) {
- var result = {};
- iteratorUtils.each(transformString.match(/\w+\d*\w*\([^)]*\)\s*/g), function(i, part) {
- var translateData = translator.parseTranslate(part);
- var scaleData = part.match(/scale\((.+?)\)/);
- var rotateData = part.match(/(rotate.)\((.+)deg\)/);
- if (translateData) {
- result.translate = translateData
- }
- if (scaleData && scaleData[1]) {
- result.scale = parseFloat(scaleData[1])
- }
- if (rotateData && rotateData[1]) {
- result[rotateData[1]] = parseFloat(rotateData[2])
- }
- });
- return result
- },
- stop: function($element, config, jumpToEnd) {
- var frameAnimation = config && config.frameAnimation;
- if (!frameAnimation) {
- return
- }
- animationFrame.cancelAnimationFrame(frameAnimation.animationFrameId);
- clearTimeout(frameAnimation.delayTimeout);
- if (jumpToEnd) {
- frameAnimation.finish()
- }
- delete config.frameAnimation
- },
- _animationStep: function($element, config) {
- var frameAnimation = config && config.frameAnimation;
- if (!frameAnimation) {
- return
- }
- var now = (new Date).valueOf();
- if (now >= frameAnimation.startTime + frameAnimation.duration) {
- frameAnimation.finish();
- return
- }
- frameAnimation.currentValue = this._calcStepValue(frameAnimation, now - frameAnimation.startTime);
- frameAnimation.draw();
- var that = this;
- frameAnimation.animationFrameId = animationFrame.requestAnimationFrame(function() {
- that._animationStep($element, config)
- })
- },
- _calcStepValue: function(frameAnimation, currentDuration) {
- var calcValueRecursively = function calcValueRecursively(from, to) {
- var result = Array.isArray(to) ? [] : {};
- var calcEasedValue = function(propName) {
- var x = currentDuration / frameAnimation.duration;
- var t = currentDuration;
- var b = 1 * from[propName];
- var c = to[propName] - from[propName];
- var d = frameAnimation.duration;
- return easing.getEasing(frameAnimation.easing)(x, t, b, c, d)
- };
- iteratorUtils.each(to, function(propName, endPropValue) {
- if ("string" === typeof endPropValue && false === parseFloat(endPropValue, 10)) {
- return true
- }
- result[propName] = "object" === _typeof(endPropValue) ? calcValueRecursively(from[propName], endPropValue) : calcEasedValue(propName)
- });
- return result
- };
- return calcValueRecursively(frameAnimation.from, frameAnimation.to)
- },
- _normalizeValue: function(value) {
- var numericValue = parseFloat(value, 10);
- if (false === numericValue) {
- return value
- }
- return numericValue
- }
- };
- var FallbackToNoAnimationStrategy = {
- initAnimation: function() {},
- animate: function() {
- return (new Deferred).resolve().promise()
- },
- stop: noop,
- isSynchronous: true
- };
- var getAnimationStrategy = function(config) {
- config = config || {};
- var animationStrategies = {
- transition: support.transition() ? TransitionAnimationStrategy : FrameAnimationStrategy,
- frame: FrameAnimationStrategy,
- noAnimation: FallbackToNoAnimationStrategy
- };
- var strategy = config.strategy || "transition";
- if ("css" === config.type && !support.transition()) {
- strategy = "noAnimation"
- }
- return animationStrategies[strategy]
- };
- var baseConfigValidator = function(config, animationType, validate, typeMessage) {
- iteratorUtils.each(["from", "to"], function() {
- if (!validate(config[this])) {
- throw errors.Error("E0010", animationType, this, typeMessage)
- }
- })
- };
- var isObjectConfigValidator = function(config, animationType) {
- return baseConfigValidator(config, animationType, function(target) {
- return isPlainObject(target)
- }, "a plain object")
- };
- var isStringConfigValidator = function(config, animationType) {
- return baseConfigValidator(config, animationType, function(target) {
- return "string" === typeof target
- }, "a string")
- };
- var CustomAnimationConfigurator = {
- setup: function() {}
- };
- var CssAnimationConfigurator = {
- validateConfig: function(config) {
- isStringConfigValidator(config, "css")
- },
- setup: function() {}
- };
- var positionAliases = {
- top: {
- my: "bottom center",
- at: "top center"
- },
- bottom: {
- my: "top center",
- at: "bottom center"
- },
- right: {
- my: "left center",
- at: "right center"
- },
- left: {
- my: "right center",
- at: "left center"
- }
- };
- var SlideAnimationConfigurator = {
- validateConfig: function(config) {
- isObjectConfigValidator(config, "slide")
- },
- setup: function($element, config) {
- var location = translator.locate($element);
- if ("slide" !== config.type) {
- var positioningConfig = "slideIn" === config.type ? config.from : config.to;
- positioningConfig.position = extend({
- of: window
- }, positionAliases[config.direction]);
- setupPosition($element, positioningConfig)
- }
- this._setUpConfig(location, config.from);
- this._setUpConfig(location, config.to);
- translator.clearCache($element)
- },
- _setUpConfig: function(location, config) {
- config.left = "left" in config ? config.left : "+=0";
- config.top = "top" in config ? config.top : "+=0";
- this._initNewPosition(location, config)
- },
- _initNewPosition: function(location, config) {
- var position = {
- left: config.left,
- top: config.top
- };
- delete config.left;
- delete config.top;
- var relativeValue = this._getRelativeValue(position.left);
- if (void 0 !== relativeValue) {
- position.left = relativeValue + location.left
- } else {
- config.left = 0
- }
- relativeValue = this._getRelativeValue(position.top);
- if (void 0 !== relativeValue) {
- position.top = relativeValue + location.top
- } else {
- config.top = 0
- }
- config[TRANSFORM_PROP] = translator.getTranslateCss({
- x: position.left,
- y: position.top
- })
- },
- _getRelativeValue: function(value) {
- var relativeValue;
- if ("string" === typeof value && (relativeValue = RELATIVE_VALUE_REGEX.exec(value))) {
- return parseInt(relativeValue[1] + "1") * relativeValue[2]
- }
- }
- };
- var FadeAnimationConfigurator = {
- setup: function($element, config) {
- var from = config.from;
- var fromOpacity = isPlainObject(from) ? config.skipElementInitialStyles ? 0 : $element.css("opacity") : String(from);
- var toOpacity;
- switch (config.type) {
- case "fadeIn":
- toOpacity = 1;
- break;
- case "fadeOut":
- toOpacity = 0;
- break;
- default:
- toOpacity = String(config.to)
- }
- config.from = {
- visibility: "visible",
- opacity: fromOpacity
- };
- config.to = {
- opacity: toOpacity
- }
- }
- };
- var PopAnimationConfigurator = {
- validateConfig: function(config) {
- isObjectConfigValidator(config, "pop")
- },
- setup: function($element, config) {
- var from = config.from;
- var to = config.to;
- var fromOpacity = "opacity" in from ? from.opacity : $element.css("opacity");
- var toOpacity = "opacity" in to ? to.opacity : 1;
- var fromScale = "scale" in from ? from.scale : 0;
- var toScale = "scale" in to ? to.scale : 1;
- config.from = {
- opacity: fromOpacity
- };
- var translate = translator.getTranslate($element);
- config.from[TRANSFORM_PROP] = this._getCssTransform(translate, fromScale);
- config.to = {
- opacity: toOpacity
- };
- config.to[TRANSFORM_PROP] = this._getCssTransform(translate, toScale)
- },
- _getCssTransform: function(translate, scale) {
- return translator.getTranslateCss(translate) + "scale(" + scale + ")"
- }
- };
- var animationConfigurators = {
- custom: CustomAnimationConfigurator,
- slide: SlideAnimationConfigurator,
- slideIn: SlideAnimationConfigurator,
- slideOut: SlideAnimationConfigurator,
- fade: FadeAnimationConfigurator,
- fadeIn: FadeAnimationConfigurator,
- fadeOut: FadeAnimationConfigurator,
- pop: PopAnimationConfigurator,
- css: CssAnimationConfigurator
- };
- var getAnimationConfigurator = function(config) {
- var result = animationConfigurators[config.type];
- if (!result) {
- throw errors.Error("E0011", config.type)
- }
- return result
- };
- var defaultJSConfig = {
- type: "custom",
- from: {},
- to: {},
- duration: 400,
- start: noop,
- complete: noop,
- easing: "ease",
- delay: 0
- };
- var defaultCssConfig = {
- duration: 400,
- easing: "ease",
- delay: 0
- };
- var setupAnimationOnElement = function() {
- var animation = this;
- var $element = animation.element;
- var config = animation.config;
- setupPosition($element, config.from);
- setupPosition($element, config.to);
- animation.configurator.setup($element, config);
- $element.data(ANIM_DATA_KEY, animation);
- if (fx.off) {
- config.duration = 0;
- config.delay = 0
- }
- animation.strategy.initAnimation($element, config);
- if (config.start) {
- var element = getPublicElement($element);
- config.start.apply(this, [element, config])
- }
- };
- var onElementAnimationComplete = function(animation) {
- var $element = animation.element;
- var config = animation.config;
- $element.removeData(ANIM_DATA_KEY);
- if (config.complete) {
- var element = getPublicElement($element);
- config.complete.apply(this, [element, config])
- }
- animation.deferred.resolveWith(this, [$element, config])
- };
- var startAnimationOnElement = function() {
- var animation = this;
- var $element = animation.element;
- var config = animation.config;
- animation.isStarted = true;
- return animation.strategy.animate($element, config).done(function() {
- onElementAnimationComplete(animation)
- }).fail(function() {
- animation.deferred.rejectWith(this, [$element, config])
- })
- };
- var stopAnimationOnElement = function(jumpToEnd) {
- var animation = this;
- var $element = animation.element;
- var config = animation.config;
- clearTimeout(animation.startTimeout);
- if (!animation.isStarted) {
- animation.start()
- }
- animation.strategy.stop($element, config, jumpToEnd)
- };
- var scopedRemoveEvent = eventUtils.addNamespace(removeEvent, "dxFXStartAnimation");
- var subscribeToRemoveEvent = function(animation) {
- eventsEngine.off(animation.element, scopedRemoveEvent);
- eventsEngine.on(animation.element, scopedRemoveEvent, function() {
- fx.stop(animation.element)
- });
- animation.deferred.always(function() {
- eventsEngine.off(animation.element, scopedRemoveEvent)
- })
- };
- var createAnimation = function(element, initialConfig) {
- var defaultConfig = "css" === initialConfig.type ? defaultCssConfig : defaultJSConfig;
- var config = extend(true, {}, defaultConfig, initialConfig);
- var configurator = getAnimationConfigurator(config);
- var strategy = getAnimationStrategy(config);
- var animation = {
- element: $(element),
- config: config,
- configurator: configurator,
- strategy: strategy,
- isSynchronous: strategy.isSynchronous,
- setup: setupAnimationOnElement,
- start: startAnimationOnElement,
- stop: stopAnimationOnElement,
- deferred: new Deferred
- };
- if (isFunction(configurator.validateConfig)) {
- configurator.validateConfig(config)
- }
- subscribeToRemoveEvent(animation);
- return animation
- };
- var animate = function(element, config) {
- var $element = $(element);
- if (!$element.length) {
- return (new Deferred).resolve().promise()
- }
- var animation = createAnimation($element, config);
- pushInAnimationQueue($element, animation);
- return animation.deferred.promise()
- };
- var pushInAnimationQueue = function($element, animation) {
- var queueData = getAnimQueueData($element);
- writeAnimQueueData($element, queueData);
- queueData.push(animation);
- if (!isAnimating($element)) {
- shiftFromAnimationQueue($element, queueData)
- }
- };
- var getAnimQueueData = function($element) {
- return $element.data(ANIM_QUEUE_KEY) || []
- };
- var writeAnimQueueData = function($element, queueData) {
- $element.data(ANIM_QUEUE_KEY, queueData)
- };
- var destroyAnimQueueData = function($element) {
- $element.removeData(ANIM_QUEUE_KEY)
- };
- var isAnimating = function($element) {
- return !!$element.data(ANIM_DATA_KEY)
- };
- var shiftFromAnimationQueue = function shiftFromAnimationQueue($element, queueData) {
- queueData = getAnimQueueData($element);
- if (!queueData.length) {
- return
- }
- var animation = queueData.shift();
- if (0 === queueData.length) {
- destroyAnimQueueData($element)
- }
- executeAnimation(animation).done(function() {
- if (!isAnimating($element)) {
- shiftFromAnimationQueue($element)
- }
- })
- };
- var executeAnimation = function(animation) {
- animation.setup();
- if (fx.off || animation.isSynchronous) {
- animation.start()
- } else {
- animation.startTimeout = setTimeout(function() {
- animation.start()
- })
- }
- return animation.deferred.promise()
- };
- var setupPosition = function($element, config) {
- if (!config || !config.position) {
- return
- }
- var win = $(window);
- var left = 0;
- var top = 0;
- var position = positionUtils.calculate($element, config.position);
- var offset = $element.offset();
- var currentPosition = $element.position();
- if (currentPosition.top > offset.top) {
- top = win.scrollTop()
- }
- if (currentPosition.left > offset.left) {
- left = win.scrollLeft()
- }
- extend(config, {
- left: position.h.location - offset.left + currentPosition.left - left,
- top: position.v.location - offset.top + currentPosition.top - top
- });
- delete config.position
- };
- var setProps = function($element, props) {
- iteratorUtils.each(props, function(key, value) {
- try {
- $element.css(key, typeUtils.isFunction(value) ? value() : value)
- } catch (e) {}
- })
- };
- var stop = function(element, jumpToEnd) {
- var $element = $(element);
- var queueData = getAnimQueueData($element);
- iteratorUtils.each(queueData, function(_, animation) {
- animation.config.delay = 0;
- animation.config.duration = 0;
- animation.isSynchronous = true
- });
- if (!isAnimating($element)) {
- shiftFromAnimationQueue($element, queueData)
- }
- var animation = $element.data(ANIM_DATA_KEY);
- if (animation) {
- animation.stop(jumpToEnd)
- }
- $element.removeData(ANIM_DATA_KEY);
- destroyAnimQueueData($element)
- };
- var fx = {
- off: false,
- animationTypes: animationConfigurators,
- animate: animate,
- createAnimation: createAnimation,
- isAnimating: isAnimating,
- stop: stop,
- _simulatedTransitionEndDelay: 100
- };
- module.exports = fx;
- module.exports.default = module.exports;
|