rc-banner-anim
Version:
banner-anim animation component for react
321 lines (290 loc) • 11.1 kB
JavaScript
import _objectWithoutProperties from 'babel-runtime/helpers/objectWithoutProperties';
import _extends from 'babel-runtime/helpers/extends';
import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
import _inherits from 'babel-runtime/helpers/inherits';
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import TweenOne from 'rc-tween-one';
import ticker from 'rc-tween-one/es/ticker';
import easeTween from 'tween-functions';
import { getGsapType, isConvert, stylesToCss, checkStyleName } from 'style-utils';
import BgElement from './BgElement';
import { currentScrollTop, currentScrollLeft, dataToArray, toArrayChildren } from './utils';
function noop() {}
var Element = function (_Component) {
_inherits(Element, _Component);
function Element(props) {
_classCallCheck(this, Element);
var _this = _possibleConstructorReturn(this, _Component.call(this, props));
_initialiseProps.call(_this);
_this.state = {
show: _this.props.show
};
_this.tickerId = -1;
_this.enterMouse = null;
_this.delayTimeout = null;
_this.show = _this.state.show;
_this.followParallax = _this.props.followParallax;
_this.transform = checkStyleName('transform');
return _this;
}
Element.prototype.componentDidMount = function componentDidMount() {
this.dom = ReactDOM.findDOMNode(this);
};
Element.prototype.componentWillReceiveProps = function componentWillReceiveProps(nextProps) {
var show = nextProps.show;
if (this.tickerId !== -1) {
ticker.clear(this.tickerId);
this.tickerId = -1;
}
var followParallax = nextProps.followParallax;
if (this.followParallax && !followParallax) {
this.reFollowParallax();
} else {
this.followParallax = followParallax;
}
this.setState({ show: show, mouseMoveType: nextProps.mouseMoveType });
};
Element.prototype.componentDidUpdate = function componentDidUpdate() {
if (this.followParallax) {
this.doms = this.followParallax.data.map(function (item) {
return document.getElementById(item.id);
});
}
};
Element.prototype.componentWillUnmount = function componentWillUnmount() {
ticker.clear(this.timeoutID);
ticker.clear(this.delayTimeout);
this.delayTimeout = -1;
this.timeoutID = -1;
};
Element.prototype.render = function render() {
var _this2 = this;
var props = _extends({}, this.props);
var style = _extends({}, props.style);
style.display = props.show ? 'block' : 'none';
style.position = 'absolute';
style.width = '100%';
if (this.props.mouseMoveType !== 'end') {
style[this.transform] = '';
}
props.style = style;
props.className = ('banner-anim-elem ' + (this.props.prefixCls || '')).trim();
var bgElem = toArrayChildren(this.props.children).filter(function (item) {
return item.type.isBannerAnimBgElement;
}).map(function (item) {
return React.cloneElement(item, { show: _this2.state.show });
});
['prefixCls', 'callBack', 'animType', 'duration', 'delay', 'ease', 'elemOffset', 'followParallax', 'show', 'type', 'direction', 'leaveChildHide', 'sync', 'ratio', 'mouseMoveType'].forEach(function (key) {
return delete props[key];
});
if (this.show === this.state.show && !this.state.mouseMoveType || this.state.mouseMoveType === 'reChild') {
if (!this.state.show) {
this.enterMouse = null;
return React.createElement(TweenOne, props, bgElem);
}
if (this.props.followParallax) {
props.onMouseMove = this.getFollowMouseMove();
}
return React.createElement(TweenOne, props, this.props.mouseMoveType === 'update' ? bgElem : this.getChildren());
}
return this.animChildren(props, style, bgElem);
};
return Element;
}(Component);
var _initialiseProps = function _initialiseProps() {
var _this3 = this;
this.onMouseMove = function (e) {
_this3.domRect = _this3.dom.getBoundingClientRect();
_this3.enterMouse = _this3.enterMouse || { x: _this3.domRect.width / 2, y: _this3.domRect.height / 2 };
_this3.domWH = {
w: _this3.domRect.width,
h: _this3.domRect.height
};
_this3.offsetTop = _this3.domRect.top + currentScrollTop();
_this3.offsetLeft = _this3.domRect.left + currentScrollLeft();
var mouseXY = {
x: e.pageX - _this3.offsetLeft,
y: e.pageY - _this3.offsetTop
};
_this3.setTicker(_this3.followParallax, mouseXY);
};
this.setTicker = function (followParallax, mouseXY) {
var callback = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : noop;
ticker.clear(_this3.tickerId);
_this3.tickerId = 'bannerElementTicker' + (Date.now() + Math.random());
var startFrame = ticker.frame;
var startX = _this3.enterMouse.x;
var startY = _this3.enterMouse.y;
var duration = followParallax.duration || 450;
var easeFunc = easeTween[followParallax.ease || 'easeOutQuad'];
var start = typeof followParallax.minMove === 'number' ? followParallax.minMove : 0.08;
ticker.wake(_this3.tickerId, function () {
var moment = (ticker.frame - startFrame) * ticker.perFrame;
var ratio = easeFunc(moment, start, 1, duration);
_this3.enterMouse.x = startX + (mouseXY.x - startX) * ratio;
_this3.enterMouse.y = startY + (mouseXY.y - startY) * ratio;
_this3.setFollowStyle(_this3.domWH);
if (moment >= duration) {
ticker.clear(_this3.tickerId);
callback();
}
});
};
this.getFollowMouseMove = function () {
var onMouseMove = void 0;
if (_this3.followParallax) {
if (_this3.followParallax.delay) {
onMouseMove = !_this3.delayTimeout ? null : _this3.state.onMouseMove;
_this3.delayTimeout = _this3.delayTimeout || ticker.timeout(function () {
_this3.setState({
onMouseMove: _this3.onMouseMove
});
}, _this3.followParallax.delay);
} else {
onMouseMove = _this3.onMouseMove;
}
}
return onMouseMove;
};
this.getFollowStyle = function (data, domWH) {
var style = {};
dataToArray(data.type).forEach(function (type) {
var mouseData = _this3.enterMouse.x;
var domData = domWH.w;
var value = data.value;
if ((type.indexOf('y') >= 0 || type.indexOf('Y') >= 0) && type !== 'opacity') {
mouseData = _this3.enterMouse.y;
domData = domWH.h;
}
var d = (mouseData - domData / 2) / (domData / 2) * value;
var _type = getGsapType(type);
var cssName = isConvert(_type);
if (cssName === 'transform') {
var transform = checkStyleName('transform');
style[transform] = style[transform] || {};
style[transform][_type] = stylesToCss(_type, d).trim();
} else if (cssName === 'filter') {
var filter = checkStyleName('filter');
style[filter] = style[filter] || {};
style[filter][_type] = stylesToCss(_type, d).trim();
} else {
style[cssName] = stylesToCss(_type, d).trim();
}
});
return style;
};
this.setFollowStyle = function (domWH) {
_this3.doms.forEach(function (item, i) {
if (!item) {
return;
}
var data = _this3.followParallax.data[i];
var style = _this3.getFollowStyle(data, domWH);
Object.keys(style).forEach(function (key) {
if (typeof style[key] === 'object') {
var styleStr = '';
Object.keys(style[key]).forEach(function (_key) {
styleStr += (' ' + _key + '(' + style[key][_key] + ')').trim();
});
item.style[key] = styleStr;
return;
}
item.style[key] = key.indexOf('backgroundPosition') >= 0 ? 'calc(' + (data.bgPosition || '0%') + ' + ' + style[key] + ' )' : style[key];
});
});
};
this.getChildren = function () {
return toArrayChildren(_this3.props.children).map(function (item) {
if (item.type === BgElement) {
return React.cloneElement(item, { show: _this3.state.show });
}
return item;
});
};
this.reFollowParallax = function () {
_this3.setTicker(_this3.followParallax, {
x: _this3.domRect.width / 2 - _this3.offsetLeft,
y: _this3.domRect.height / 2 - _this3.offsetTop
}, function () {
_this3.followParallax = null;
});
};
this.animEnd = function () {
var type = _this3.state.show ? 'enter' : 'leave';
_this3.props.callBack(type);
_this3.setState({ show: _this3.props.show, mouseMoveType: null });
};
this.animChildren = function (props, style, bgElem) {
var _props = _this3.props,
elemOffset = _props.elemOffset,
leaveChildHide = _props.leaveChildHide,
ratio = _props.ratio,
animType = _props.animType,
direction = _props.direction,
mouseMoveType = _props.mouseMoveType,
ease = _props.ease,
duration = _props.duration,
delay = _props.delay,
show = _props.show,
sync = _props.sync,
component = _props.component;
if (_this3.tickerId) {
ticker.clear(_this3.tickerId);
}
if (_this3.delayTimeout) {
ticker.clear(_this3.delayTimeout);
_this3.delayTimeout = null;
}
style.display = 'block';
props.component = component;
_this3.show = _this3.state.show;
style.zIndex = _this3.state.show ? 1 : 0;
props.children = show && !sync ? bgElem : _this3.getChildren();
var childrenToRender = React.createElement(TweenOne, props);
var type = _this3.state.show ? 'enter' : 'leave';
var $ratio = mouseMoveType === 'end' && ratio <= 0.3 ? 1 - ratio : ratio;
var tag = animType(childrenToRender, type, direction, {
ease: ease,
duration: duration,
delay: delay,
onComplete: _this3.animEnd
}, elemOffset, leaveChildHide, $ratio, _this3.state.mouseMoveType === 'update');
var tagProps = _objectWithoutProperties(tag.props, []);
if (tagProps.animation) {
tagProps.moment = (tagProps.animation.duration + tagProps.animation.delay) * $ratio || 0;
tagProps.paused = _this3.state.mouseMoveType === 'update' || $ratio === 1;
}
return React.cloneElement(tag, tagProps);
};
};
Element.propTypes = {
children: PropTypes.any,
style: PropTypes.object,
prefixCls: PropTypes.string,
component: PropTypes.any,
elemOffset: PropTypes.object,
type: PropTypes.string,
animType: PropTypes.func,
ease: PropTypes.string,
duration: PropTypes.number,
delay: PropTypes.number,
direction: PropTypes.string,
callBack: PropTypes.func,
followParallax: PropTypes.any,
show: PropTypes.bool,
leaveChildHide: PropTypes.bool,
sync: PropTypes.bool,
ratio: PropTypes.number,
mouseMoveType: PropTypes.string
};
Element.defaultProps = {
component: 'div',
callBack: noop,
delay: 0
};
Element.BgElement = BgElement;
Element.isBannerAnimElement = true;
export default Element;