forked from andrepolischuk/react-rotation
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
115 lines (101 loc) · 3.93 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
import React, { cloneElement, Children, Component, PropTypes } from 'react';
import { findDOMNode } from 'react-dom';
export default class Rotation extends Component {
static propTypes = {
className: PropTypes.string,
cycle: PropTypes.bool,
scroll: PropTypes.bool,
vertical: PropTypes.bool,
onChange: PropTypes.func,
children: PropTypes.arrayOf(PropTypes.element).isRequired
};
static defaultProps = {
cycle: false,
scroll: true,
vertical: false
};
constructor(props) {
super(props);
this.handleWheel = this.handleWheel.bind(this);
this.handleTouchStart = this.handleTouchStart.bind(this);
this.handleTouchMove = this.handleTouchMove.bind(this);
this.handleTouchEnd = this.handleTouchEnd.bind(this);
}
state = { current: 0 };
componentDidMount() {
const el = findDOMNode(this);
if (this.props.scroll) el.addEventListener('wheel', this.handleWheel, false);
el.addEventListener('touchstart', this.handleTouchStart, false);
el.addEventListener('touchmove', this.handleTouchMove, false);
el.addEventListener('touchend', this.handleTouchEnd, false);
el.addEventListener('mousedown', this.handleTouchStart, false);
el.addEventListener('mousemove', this.handleTouchMove, false);
document.addEventListener('mouseup', this.handleTouchEnd, false);
}
componentWillUnmount() {
const el = findDOMNode(this);
if (this.props.scroll) el.removeEventListener('wheel', this.handleWheel, false);
el.removeEventListener('touchstart', this.handleTouchStart, false);
el.removeEventListener('touchmove', this.handleTouchMove, false);
el.removeEventListener('touchend', this.handleTouchEnd, false);
el.removeEventListener('mousedown', this.handleTouchStart, false);
el.removeEventListener('mousemove', this.handleTouchMove, false);
document.removeEventListener('mouseup', this.handleTouchEnd, false);
}
setCurrentFrame(frame) {
const { cycle, children, onChange } = this.props;
const length = children.length;
let current = frame;
if (current < 0) current = cycle ? current + length : 0;
if (current > length - 1) current = cycle ? current - length : length - 1;
if (current !== this.state.current) {
this.setState({ current });
if (typeof onChange === 'function') onChange(current);
}
}
handleWheel(event) {
event.preventDefault();
const { deltaY } = event;
const delta = deltaY === 0 ? 0 : deltaY / Math.abs(deltaY);
this.setCurrentFrame(this.state.current + delta);
}
handleTouchStart(event) {
event.preventDefault();
this.pointerPosition = this.calculatePointerPosition(event);
this.startFrame = this.state.current;
}
handleTouchMove(event) {
const { vertical, children } = this.props;
event.preventDefault();
if (typeof this.pointerPosition !== 'number') return;
const { offsetWidth, offsetHeight } = findDOMNode(this);
const pointer = this.calculatePointerPosition(event);
const max = vertical ? offsetHeight : offsetWidth;
const offset = pointer - this.pointerPosition;
const delta = Math.floor(offset / max * children.length);
this.setCurrentFrame(this.startFrame + delta);
}
handleTouchEnd(event) {
event.preventDefault();
this.pointerPosition = null;
this.startFrame = null;
}
calculatePointerPosition(event) {
const touch = event.type.indexOf('touch') === 0 ? event.changedTouches[0] : event;
const { clientX, clientY } = touch;
const { offsetTop, offsetLeft } = findDOMNode(this);
return this.props.vertical ? clientY - offsetTop : clientX - offsetLeft;
}
render() {
const { current } = this.state;
const { children, className } = this.props;
return (
<div className={className} style={{ position: 'relative' }}>
{Children.map(children, (child, i) => cloneElement(
child,
{ style: { width: '100%', display: current === i ? 'block' : 'none' } }
))}
</div>
);
}
}