Skip to content

Commit e7a5eab

Browse files
committed
Initial commit
1 parent 8e6d2e1 commit e7a5eab

File tree

6 files changed

+256
-2
lines changed

6 files changed

+256
-2
lines changed

README.md

Lines changed: 0 additions & 2 deletions
This file was deleted.

package.json

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"name": "react-gesture-carousel",
3+
"version": "1.0.0",
4+
"description": "",
5+
"keywords": [],
6+
"main": "src/index.js",
7+
"dependencies": {
8+
"react": "16.8.6",
9+
"react-dom": "16.8.6",
10+
"react-scripts": "3.0.1"
11+
},
12+
"devDependencies": {
13+
"typescript": "3.3.3"
14+
},
15+
"scripts": {
16+
"start": "react-scripts start",
17+
"build": "react-scripts build",
18+
"test": "react-scripts test --env=jsdom",
19+
"eject": "react-scripts eject"
20+
},
21+
"browserslist": [
22+
">0.2%",
23+
"not dead",
24+
"not ie <= 11",
25+
"not op_mini all"
26+
]
27+
}

public/index.html

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="utf-8">
6+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
7+
<meta name="theme-color" content="#000000">
8+
<!--
9+
manifest.json provides metadata used when your web app is added to the
10+
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
11+
-->
12+
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
13+
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
14+
<!--
15+
Notice the use of %PUBLIC_URL% in the tags above.
16+
It will be replaced with the URL of the `public` folder during the build.
17+
Only files inside the `public` folder can be referenced from the HTML.
18+
19+
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
20+
work correctly both with client-side routing and a non-root public URL.
21+
Learn how to configure a non-root public URL by running `npm run build`.
22+
-->
23+
<title>React App</title>
24+
</head>
25+
26+
<body>
27+
<noscript>
28+
You need to enable JavaScript to run this app.
29+
</noscript>
30+
<div id="root"></div>
31+
<!--
32+
This HTML file is a template.
33+
If you open it directly in the browser, you will see an empty page.
34+
35+
You can add webfonts, meta tags, or analytics to this file.
36+
The build step will place the bundled scripts into the <body> tag.
37+
38+
To begin the development, run `npm start` or `yarn start`.
39+
To create a production bundle, use `npm run build` or `yarn build`.
40+
-->
41+
</body>
42+
43+
</html>

src/carousel.jsx

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import React from "react";
2+
import "./styles.css";
3+
4+
export default class Carousel extends React.Component {
5+
constructor(props) {
6+
super(props);
7+
8+
this.draggableRef = React.createRef();
9+
10+
this.state = {
11+
dragging: false,
12+
dragStartX: 0,
13+
dragStartTime: 0,
14+
carouselPosition: 0, //This can be a value between 0 - 360,
15+
change: 0,
16+
width: 0,
17+
velocity: 0
18+
};
19+
20+
this.onDragStartMouse = this.onDragStartMouse.bind(this);
21+
this.onDragStartTouch = this.onDragStartTouch.bind(this);
22+
this.onMouseMove = this.onMouseMove.bind(this);
23+
this.onTouchMove = this.onTouchMove.bind(this);
24+
this.updatePosition = this.updatePosition.bind(this);
25+
this.onDragEnd = this.onDragEnd.bind(this);
26+
this.onDragStart = this.onDragStart.bind(this);
27+
this.onDragEndMouse = this.onDragEndMouse.bind(this);
28+
this.onDragEndTouch = this.onDragEndTouch.bind(this);
29+
}
30+
31+
componentDidMount() {
32+
window.addEventListener("mouseup", this.onDragEndMouse);
33+
window.addEventListener("touchend", this.onDragEndTouch);
34+
this.setState(() => ({
35+
width: this.draggableRef.current.getBoundingClientRect().width
36+
}));
37+
}
38+
39+
componentWillUnmount() {
40+
window.removeEventListener("mouseup", this.onDragEndMouse);
41+
window.removeEventListener("touchend", this.onDragEndTouch);
42+
}
43+
44+
onDragStart(clientX) {
45+
this.setState(() => ({ dragStartX: clientX, dragging: true }));
46+
requestAnimationFrame(this.updatePosition);
47+
}
48+
49+
onDragEnd() {
50+
if (this.state.dragging) {
51+
this.setState(() => ({ dragging: false, change: 0 }));
52+
}
53+
}
54+
55+
updatePosition() {
56+
//When we start dragging updatePosition is called once, then it must keep
57+
//calling itself so we can continue to update the position of the current item,
58+
//thats why the following line is here, it will terminate when we mouseup and dragging becomes false
59+
if (this.state.dragging) requestAnimationFrame(this.updatePosition);
60+
61+
const now = Date.now();
62+
const elapsed = now - this.state.dragStartTime;
63+
64+
if (this.state.dragging && elapsed > 20) {
65+
console.log("carouselPos: ", this.state.carouselPosition);
66+
this.draggableRef.current.style.transform = `rotate3d(0,1,0,${
67+
this.state.carouselPosition
68+
}deg)`;
69+
70+
this.setState(() => ({ dragStartTime: Date.now() }));
71+
}
72+
}
73+
74+
onMouseMove(e) {
75+
const change = e.clientX - this.state.dragStartX;
76+
this.setState(prevState => ({
77+
change: change,
78+
carouselPosition: this.calculateCarouselPosition(
79+
change - prevState.change,
80+
prevState.carouselPosition,
81+
prevState.width
82+
)
83+
}));
84+
}
85+
86+
onTouchMove(e) {
87+
const touch = e.targetTouches[0];
88+
const change = touch.clientX - this.state.dragStartX;
89+
this.setState(prevState => ({
90+
change: change,
91+
carouselPosition: this.calculateCarouselPosition(
92+
change - prevState.change,
93+
prevState.carouselPosition,
94+
prevState.width
95+
)
96+
}));
97+
}
98+
99+
onDragStartMouse(e) {
100+
this.onDragStart(e.clientX);
101+
window.addEventListener("mousemove", this.onMouseMove);
102+
}
103+
104+
onDragStartTouch(e) {
105+
const touch = e.targetTouches[0];
106+
this.onDragStart(touch.clientX);
107+
window.addEventListener("touchmove", this.onTouchMove);
108+
}
109+
110+
onDragEndMouse(e) {
111+
window.removeEventListener("mousemove", this.onMouseMove);
112+
this.onDragEnd();
113+
}
114+
115+
onDragEndTouch(e) {
116+
window.removeEventListener("touchmove", this.onTouchMove);
117+
this.onDragEnd();
118+
}
119+
120+
calculateCarouselPosition(currentMovement, previousCarouselState, width) {
121+
//current movement is something like +40 or -20 or whatever, depending on left or right movement
122+
// previouCarousel is something between 1 & 360, so we need to map changes to that, we may need to factor in the
123+
// component width when mapping the currentMovement to the carousel change
124+
const cappedMovement =
125+
currentMovement > 0
126+
? Math.min(currentMovement, width)
127+
: Math.max(currentMovement, -width);
128+
const degreesMoved = (cappedMovement / width) * 360 + previousCarouselState; //may be -30 degrees or + 10 degrees? who knows
129+
//which percentage of the current div have we moved? and how many degrees is that for our 360 carousel
130+
//If mappedCarouselMovement + previousCarousel state is > 360, then we take the amount we go over by and instead add that to 0,
131+
//so we always have a number between 0 and 360. Same for < 0, if its -30 after the calculation, then we take that different and
132+
//subtract it from 360
133+
const currentCarouselDegrees =
134+
degreesMoved > 360
135+
? degreesMoved - 360
136+
: degreesMoved < 0
137+
? degreesMoved + 360
138+
: degreesMoved;
139+
140+
return currentCarouselDegrees;
141+
}
142+
143+
render() {
144+
const { change, carouselPosition } = this.state;
145+
146+
return (
147+
<div>
148+
<h1>hey</h1>
149+
<div
150+
ref={this.draggableRef}
151+
onMouseDown={this.onDragStartMouse}
152+
onTouchStart={this.onDragStartTouch}
153+
className="spinText"
154+
>
155+
touch move me wherever necessary
156+
</div>
157+
{/* <Carousel360 imageNumber={carouselPosition} /> */}
158+
{carouselPosition}
159+
</div>
160+
);
161+
}
162+
}

src/index.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import React from "react";
2+
import ReactDOM from "react-dom";
3+
4+
import "./styles.css";
5+
import Carousel from "./carousel";
6+
7+
function App() {
8+
return (
9+
<div className="App">
10+
<Carousel />
11+
</div>
12+
);
13+
}
14+
15+
const rootElement = document.getElementById("root");
16+
ReactDOM.render(<App />, rootElement);

src/styles.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
.App {
2+
font-family: sans-serif;
3+
text-align: center;
4+
}
5+
6+
.spinText {
7+
display: inline-block;
8+
}

0 commit comments

Comments
 (0)