react-turntable
Version:
A HTML5 Turntable component for React
399 lines (341 loc) • 16.8 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
exports.easeOut = easeOut;
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _classnames = require('classnames');
var _classnames2 = _interopRequireDefault(_classnames);
var _propTypes = require('prop-types');
var _propTypes2 = _interopRequireDefault(_propTypes);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } /**
* @author Jinke.Li
* @version 1.2.7
* @description https://juejin.im/post/5992b6065188257dd3664dbc
*/
function easeOut(t, b, c, d) {
if ((t /= d / 2) < 1) return c / 2 * t * t + b;
return -c / 2 * (--t * (t - 2) - 1) + b;
}
var prefix = 'react-turntable';
var ReactTurntable = function (_PureComponent) {
_inherits(ReactTurntable, _PureComponent);
function ReactTurntable(props) {
_classCallCheck(this, ReactTurntable);
var _this = _possibleConstructorReturn(this, (ReactTurntable.__proto__ || Object.getPrototypeOf(ReactTurntable)).call(this, props));
_this.state = {
isRotate: false,
startRotate: 0
};
_this.noticePrize = function () {
return _this.__noticePrize__REACT_HOT_LOADER__.apply(_this, arguments);
};
_this.rotateTurntable = function () {
return _this.__rotateTurntable__REACT_HOT_LOADER__.apply(_this, arguments);
};
_this.getSelectedPrize = function () {
return _this.__getSelectedPrize__REACT_HOT_LOADER__.apply(_this, arguments);
};
_this.onStartRotate = function () {
return _this.__onStartRotate__REACT_HOT_LOADER__.apply(_this, arguments);
};
_this.stopRotate = function () {
return _this.__stopRotate__REACT_HOT_LOADER__.apply(_this, arguments);
};
_this.initTurntable = function () {
return _this.__initTurntable__REACT_HOT_LOADER__.apply(_this, arguments);
};
_this.getTurntable = function () {
return _this.__getTurntable__REACT_HOT_LOADER__.apply(_this, arguments);
};
_this.canvas = null;
_this.ctx = null;
_this.animateId = null;
return _this;
}
_createClass(ReactTurntable, [{
key: '__getTurntable__REACT_HOT_LOADER__',
value: function __getTurntable__REACT_HOT_LOADER__() {
if (this.props.getTurntable) {
this.props.getTurntable({
start: this.onStartRotate,
stop: this.stopRotate
});
}
}
}, {
key: '__initTurntable__REACT_HOT_LOADER__',
value: function __initTurntable__REACT_HOT_LOADER__() {
var _props = this.props,
width = _props.width,
height = _props.height,
prizes = _props.prizes;
this.prizes = prizes;
this.startRotate = 0;
this.rotateTime = 0;
this.rotateAllTime = 0;
this.rotateChange = 0;
this.ctx = this.canvas.getContext('2d');
this.canvas.width = width;
this.canvas.height = height;
this.awardRotate = Math.PI * 2 / prizes.length;
this.centerX = this.canvas.width / 2;
this.centerY = this.canvas.height / 2;
this.R = this.canvas.width / 2 - 20;
this.TEXT_R = this.R - 50;
this.INSERT_R = 0;
this.drawTurntable();
}
}, {
key: '__stopRotate__REACT_HOT_LOADER__',
value: function __stopRotate__REACT_HOT_LOADER__() {
this.setState({ isRotate: false });
window.cancelAnimationFrame(this.animateId);
this.noticePrize();
}
}, {
key: '__onStartRotate__REACT_HOT_LOADER__',
value: function __onStartRotate__REACT_HOT_LOADER__() {
var _this2 = this;
var _props2 = this.props,
speed = _props2.speed,
duration = _props2.duration,
onStart = _props2.onStart;
if (this.state.isRotate) return;
if (onStart && !onStart()) return;
this.setState({ isRotate: true }, function () {
_this2.rotateTime = 0;
_this2.rotateAllTime = Math.random() * 5 + duration;
_this2.rotateChange = Math.random() * 10 + speed / 100;
_this2.rotateTurntable();
});
}
}, {
key: '__getSelectedPrize__REACT_HOT_LOADER__',
value: function __getSelectedPrize__REACT_HOT_LOADER__() {
var startAngle = this.startRotate * 180 / Math.PI,
awardAngle = this.awardRotate * 180 / Math.PI,
pointerAngle = 90,
overAngle = (startAngle + pointerAngle) % 360,
restAngle = 360 - overAngle,
index = Math.floor(restAngle / awardAngle);
return this.prizes[index];
}
}, {
key: '__rotateTurntable__REACT_HOT_LOADER__',
value: function __rotateTurntable__REACT_HOT_LOADER__() {
this.rotateTime += 20;
if (this.rotateTime >= this.rotateAllTime) {
this.setState({ isRotate: false });
this.noticePrize();
return;
}
var _rotateChange = (this.rotateChange - easeOut(this.rotateTime, 0, this.rotateChange, this.rotateAllTime)) * (Math.PI / 180);
this.startRotate += _rotateChange;
this.drawTurntable();
this.animateId = requestAnimationFrame(this.rotateTurntable);
}
}, {
key: '__noticePrize__REACT_HOT_LOADER__',
value: function __noticePrize__REACT_HOT_LOADER__() {
var prize = this.getSelectedPrize();
this.props.onComplete && this.props.onComplete(prize);
}
}, {
key: 'render',
value: function render() {
var _this3 = this;
var _props3 = this.props,
clickText = _props3.clickText,
style = _props3.style,
className = _props3.className,
width = _props3.width,
height = _props3.height,
hiddenButton = _props3.hiddenButton;
var styles = _extends({}, style, { width: width, height: height });
return _react2.default.createElement(
'div',
{
className: (0, _classnames2.default)(prefix, prefix + '-section', className),
style: styles
},
_react2.default.createElement('canvas', {
id: 'react-turntable-section-canvas',
ref: function ref(node) {
return _this3.canvas = node;
}
}),
!hiddenButton && (Object.is(typeof clickText === 'undefined' ? 'undefined' : _typeof(clickText), 'string') ? _react2.default.createElement(
'div',
{
className: 'react-turntable-section-btn',
onClick: this.onStartRotate
},
clickText
) : _react2.default.createElement(
'div',
{ onClick: this.onStartRotate },
clickText
))
);
}
}, {
key: 'drawTurntable',
value: function drawTurntable() {
var ctx = this.ctx;
ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
var _props4 = this.props,
primaryColor = _props4.primaryColor,
secondaryColor = _props4.secondaryColor,
_props4$fontStyle = _props4.fontStyle,
fontVertical = _props4$fontStyle.fontVertical,
fontWeight = _props4$fontStyle.fontWeight,
fontFamily = _props4$fontStyle.fontFamily,
size = _props4$fontStyle.size,
color = _props4$fontStyle.color;
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = this.prizes.entries()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var _step$value = _slicedToArray(_step.value, 2),
i = _step$value[0],
prize = _step$value[1];
var _currentStartRotate = this.startRotate + this.awardRotate * i;
var _currentEndRotate = _currentStartRotate + this.awardRotate;
this.ctx.save();
i % 2 === 0 ? ctx.fillStyle = primaryColor : ctx.fillStyle = secondaryColor;
ctx.beginPath();
ctx.arc(this.centerX, this.centerY, this.R, _currentStartRotate, _currentEndRotate, false);
ctx.arc(this.centerX, this.centerY, this.INSERT_R, _currentEndRotate, _currentStartRotate, true);
ctx.fill();
ctx.closePath();
ctx.restore();
ctx.save();
ctx.beginPath();
ctx.font = fontWeight + ' ' + (/.*px$/.test(size) ? size : size + 'px') + ' ' + fontFamily;
ctx.fillStyle = color;
ctx.textBaseline = 'middle';
var currentX = Math.cos(_currentStartRotate + this.awardRotate / 2) * this.TEXT_R;
var currentY = Math.sin(_currentStartRotate + this.awardRotate / 2) * this.TEXT_R;
ctx.translate(this.centerX + currentX, this.centerY + currentY);
ctx.rotate(_currentStartRotate + this.awardRotate / 2 + Math.PI / 2);
var _ctx$measureText = ctx.measureText(prize),
fontWidth = _ctx$measureText.width;
if (fontVertical === true) {
ctx.translate(0, Math.min(fontWidth, 25));
ctx.rotate(90 / 180 * Math.PI);
}
ctx.fillText(prize, -fontWidth / 2, 0);
ctx.closePath();
ctx.restore();
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
}
}, {
key: 'destroyContext',
value: function destroyContext() {
window.cancelAnimationFrame(this.animateId);
delete this.canvas;
delete this.ctx;
}
}, {
key: 'compatibilityFrame',
value: function compatibilityFrame() {
window.requestAnimFrame = function () {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function (callback) {
return window.setTimeout(callback, 1000 / 60);
};
}();
window.cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame;
}
}, {
key: 'componentWillMount',
value: function componentWillMount() {
if (this.props.prizes.length < 2) throw new Error('options prizes It needs to be an array , Not less than two');
}
}, {
key: 'componentWillUnmount',
value: function componentWillUnmount() {
this.destroyContext();
}
}, {
key: 'componentDidMount',
value: function componentDidMount() {
this.compatibilityFrame();
this.initTurntable();
this.getTurntable();
}
}]);
return ReactTurntable;
}(_react.PureComponent);
ReactTurntable.defaultProps = {
width: 500,
height: 500,
speed: 1000, //旋转速度
duration: 5000, //旋转时间
prizes: [],
clickText: 'Click',
primaryColor: '#83AF9B',
secondaryColor: '#C8C8A9',
fontStyle: {
color: '#fff',
size: '14px',
fontWeight: 'bold',
fontVertical: false,
fontFamily: 'Microsoft YaHei'
},
onStart: function onStart() {
return true;
},
hiddenButton: false
};
ReactTurntable.propTypes = {
width: _propTypes2.default.number.isRequired,
height: _propTypes2.default.number.isRequired,
prizes: _propTypes2.default.array.isRequired,
clickText: _propTypes2.default.oneOfType([_propTypes2.default.string, _propTypes2.default.object]),
primaryColor: _propTypes2.default.string,
secondaryColor: _propTypes2.default.string,
speed: _propTypes2.default.number,
duration: _propTypes2.default.number,
onComplete: _propTypes2.default.func,
onStart: _propTypes2.default.func,
fontVertical: _propTypes2.default.bool,
fontStyle: _propTypes2.default.object,
hiddenButton: _propTypes2.default.bool
};
var _default = ReactTurntable;
exports.default = _default;
;
var _temp = function () {
if (typeof __REACT_HOT_LOADER__ === 'undefined') {
return;
}
__REACT_HOT_LOADER__.register(easeOut, 'easeOut', 'src/index.js');
__REACT_HOT_LOADER__.register(prefix, 'prefix', 'src/index.js');
__REACT_HOT_LOADER__.register(ReactTurntable, 'ReactTurntable', 'src/index.js');
__REACT_HOT_LOADER__.register(_default, 'default', 'src/index.js');
}();
;