Skip to content

Instantly share code, notes, and snippets.

@hueyAtFetchly
Last active August 4, 2020 14:28
Show Gist options
  • Save hueyAtFetchly/f09e9ffef21d8fcb42035e9b8446385b to your computer and use it in GitHub Desktop.
Save hueyAtFetchly/f09e9ffef21d8fcb42035e9b8446385b to your computer and use it in GitHub Desktop.
Simple React Carousel
import React, {Component} from 'react'
export default class Swipeable extends Component {
constructor(props) {
super(props)
this.handleMouseMove = this.handleMouseMove.bind(this)
this.handleMouseDown = this.handleMouseDown.bind(this)
this.handleMouseUp = this.handleMouseUp.bind(this)
this.handleMouseLeave = this.handleMouseLeave.bind(this)
this.handleTouchStart = this.handleTouchStart.bind(this)
this.handleTouchMove = this.handleTouchMove.bind(this)
this.handleTouchEnd = this.handleTouchEnd.bind(this)
this.state = {
left: props.left || 0
}
}
componentDidUpdate(prevProps){
if(prevProps.left !== this.props.left){
this.setState({ left: this.props.left })
}
}
handleTouchStart(event) {
event.preventDefault();
this.handleStart(event.targetTouches[0].clientX);
}
handleTouchMove(event) {
this.handleMove(event.targetTouches[0].clientX);
}
handleTouchEnd() {
this.handleEnd();
}
handleMouseDown(event) {
event.preventDefault();
this.handleStart(event.clientX);
}
handleMouseMove(event) {
this.handleMove(event.clientX);
}
handleMouseUp(){
this.handleEnd()
}
handleMouseLeave(){
this.handleMouseUp()
}
handleStart(clientX) {
if (this.state.intervalId !== null) {
window.clearInterval(this.state.intervalId);
}
this.setState({
originalOffset: this.state.left,
velocity: 0,
timeOfLastDragEvent: Date.now(),
touchStartX: clientX,
beingTouched: true,
intervalId: null
});
}
get speedDividend(){
return this.props.speed || 3
}
handleEnd() {
this.setState({
velocity: this.state.velocity,
touchStartX: 0,
beingTouched: false,
});
}
handleMove(clientX) {
if (this.state.beingTouched) {
const touchX = clientX;
const currTime = Date.now();
const elapsed = currTime - this.state.timeOfLastDragEvent;
const velocity = ((touchX - this.state.prevTouchX) / (elapsed));
let deltaX = ((touchX - this.state.touchStartX) / this.speedDividend ) + this.state.originalOffset;
const leastLeft = (this.props.items.length-1)*(this.props.cardWidth || this.props.cardWidthPercent) * -1
if (deltaX < leastLeft) {
deltaX = leastLeft
} else if (deltaX > 0) {
deltaX = 0;
}
this.setState({
left: deltaX,
velocity,
timeOfLastDragEvent: currTime,
prevTouchX: touchX
});
this.props.onMove ? this.props.onMove(this.activeIndex(deltaX)) : null
}
}
activeIndex(left){
return Math.abs(Math.round(((left * 1) / this.props.cardWidthPercent) - this.props.indexSwitchOffset))
}
render() {
return (
<div
className={'horizontal-carousel'}
style={{height: this.props.height}}
onTouchStart={e => this.handleTouchStart(e)}
onTouchMove={e => this.handleTouchMove(e)}
onTouchEnd={() => this.handleTouchEnd()}
onMouseDown={e => this.handleMouseDown(e)}
onMouseMove={e => this.handleMouseMove(e)}
onMouseUp={() => this.handleMouseUp()}
onMouseLeave={() => this.handleMouseLeave()}
>
{this.props.items.map((item, i)=>{
return (
<div className={'test-card'} style={{
width: this.props.cardWidth ? this.props.cardWidth : `${this.props.cardWidthPercent}%`,
position: 'relative',
left: this.props.cardWidth ? this.state.left : `${this.state.left}%`,
height: this.props.height -10,
}} key={i}>
{item}
</div>
)
})}
</div>
)
}
}
@hueyAtFetchly
Copy link
Author

.test-card{
    display: inline-block;
}
.horizontal-carousel{
    width: 100%;
    padding-top:5px;
    white-space: nowrap;
    overflow-x: hidden;
    overflow-y: hidden;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment