react-floating
Version:
Floating React component
202 lines (158 loc) • 5.92 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require('babel-runtime/helpers/inherits');
var _inherits3 = _interopRequireDefault(_inherits2);
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _reactAddonsShallowCompare = require('react-addons-shallow-compare');
var _reactAddonsShallowCompare2 = _interopRequireDefault(_reactAddonsShallowCompare);
require('raf');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var Floating = function (_Component) {
(0, _inherits3.default)(Floating, _Component);
function Floating() {
var _Object$getPrototypeO;
var _temp, _this, _ret;
(0, _classCallCheck3.default)(this, Floating);
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
return _ret = (_temp = (_this = (0, _possibleConstructorReturn3.default)(this, (_Object$getPrototypeO = (0, _getPrototypeOf2.default)(Floating)).call.apply(_Object$getPrototypeO, [this].concat(args))), _this), _this.onDeviceOrientation = function (_ref) {
var beta = _ref.beta;
var gamma = _ref.gamma;
_this.frame = requestAnimationFrame(function () {
var maxMobileRange = _this.props.maxMobileRange;
var translateX = void 0;
var translateY = void 0;
if (window.orientation) {
translateX = Floating.getDegreeSin(beta) * maxMobileRange;
translateY = Floating.getDegreeSin(gamma * 2) * maxMobileRange;
} else {
translateX = Floating.getDegreeSin(gamma * 2) * maxMobileRange;
translateY = Floating.getDegreeSin(beta) * maxMobileRange;
}
_this.addFloatingToElement(translateX, translateY, 0);
});
}, _this.onMouseMove = function (_ref2) {
var clientX = _ref2.clientX;
var clientY = _ref2.clientY;
_this.frame = requestAnimationFrame(function () {
var translateX = _this.state.percentTranslateX * (clientX - _this.state.elementLeft - _this.state.halfElementWidth);
var translateY = _this.state.percentTranslateY * (clientY - _this.state.elementTop - _this.state.halfElementHeight);
_this.addFloatingToElement(translateX, translateY, 0);
});
}, _this.onResize = function () {
var node = _this.refs.floating;
var _Floating$getElementO = Floating.getElementOffset(node);
var top = _Floating$getElementO.top;
var left = _Floating$getElementO.left;
_this.setState({
percentTranslateX: _this.props.maxRange / (window.innerWidth / 2),
percentTranslateY: _this.props.maxRange / (window.innerHeight / 2),
elementTop: top,
elementLeft: left,
halfElementWidth: node.offsetWidth / 2,
halfElementHeight: node.offsetHeight / 2
});
}, _temp), (0, _possibleConstructorReturn3.default)(_this, _ret);
}
(0, _createClass3.default)(Floating, [{
key: 'render',
value: function render() {
return _react2.default.createElement(
'div',
{
className: this.props.className,
style: this.props.style,
ref: 'floating'
},
this.props.children || null
);
}
}, {
key: 'shouldComponentUpdate',
value: function shouldComponentUpdate(nextProps, nextState) {
return (0, _reactAddonsShallowCompare2.default)(this, nextProps, nextState);
}
}, {
key: 'componentDidMount',
value: function componentDidMount() {
this.onResize();
window.addEventListener('deviceorientation', this.onDeviceOrientation);
window.addEventListener('mousemove', this.onMouseMove);
window.addEventListener('resize', this.onResize);
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
if (this.frame) {
cancelAnimationFrame(this.frame);
}
window.removeEventListener('resize', this.onResize);
window.removeEventListener('mousemove', this.onMouseMove);
window.removeEventListener('deviceorientation', this.onDeviceOrientation);
}
}, {
key: 'addFloatingToElement',
value: function addFloatingToElement(x, y, z) {
if (!this.refs.floating) {
return;
}
if (this.props.reverse) {
x = -x;
y = -y;
z = -z;
}
var transform = 'translateX(' + x + 'px) translateY(' + y + 'px) translateZ(' + z + 'px)';
if (this.props.scale) {
transform += ' scale(' + this.props.scale + ')';
}
this.refs.floating.style.WebkitTransform = transform;
this.refs.floating.style.transform = transform;
}
// beta = x [-180; 180];
// gamma = y [-90; 90];
// alpha = z [0; 360];
}], [{
key: 'getDegreeSin',
value: function getDegreeSin(degree) {
return Number(Math.sin(Math.PI * degree / 180).toFixed(3));
}
}, {
key: 'getElementOffset',
value: function getElementOffset(elem) {
var top = 0;
var left = 0;
while (elem) {
top += parseFloat(elem.offsetTop);
left += parseFloat(elem.offsetLeft);
elem = elem.offsetParent;
}
return {
top: Math.round(top),
left: Math.round(left)
};
}
}]);
return Floating;
}(_react.Component);
Floating.propTypes = {
maxMobileRange: _react.PropTypes.number.isRequired,
maxRange: _react.PropTypes.number.isRequired,
className: _react.PropTypes.string,
children: _react.PropTypes.any,
reverse: _react.PropTypes.bool,
scale: _react.PropTypes.number,
style: _react.PropTypes.object
};
exports.default = Floating;