Created
April 21, 2017 07:02
-
-
Save zapkub/3328e2d9fe1c9739c3be9580fcdeb006 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// @flow | |
import React from 'react'; | |
import { Textfit } from 'react-textfit'; | |
import _ from 'lodash'; | |
import { TweenMax, Back, Power4 } from 'gsap'; | |
import type { Song } from '../models'; | |
import styles from './SongList.css'; | |
export class PlayerSongList extends React.Component { | |
constructor(props) { | |
super(props); | |
this.state = { | |
deg: 0, | |
}; | |
this.state.shuffleList = props.songList.map(() => _.shuffle(props.fullSongList)); | |
this.toRadius = this.toRadius.bind(this); | |
this.getApothem = this.getApothem.bind(this); | |
this.calculateSongStyle = this.calculateSongStyle.bind(this); | |
this.start = this.start.bind(this); | |
} | |
componentDidMount() { | |
// setTimeout(() => TweenMax.to('#row_0', 2, { rotationX: '180deg' }), 400); | |
if (this.props.selectedRoundName === 'round1') { | |
this.start(); | |
} | |
} | |
start() { | |
TweenMax.to(this.refs.row_0, 5, { rotationX: '-=1800deg' }); | |
TweenMax.to(this.refs.row_1, 7, { rotationX: '-=1800deg', ease: Power4.easeOut }); | |
TweenMax.to(this.refs.row_2, 10, { rotationX: '-=1800deg', ease: Back.easeOut.config(1.7) }); | |
} | |
getApothem() { | |
return 100 / (2 * Math.tan(this.toRadius(180 / (this.props.fullSongList.length + 1)))); | |
} | |
toRadius(deg) { | |
return deg / 180 * Math.PI; | |
} | |
calculateSongStyle(index) { | |
const degPerItem = 360 / (this.props.fullSongList.length + 1); | |
const deg = degPerItem * index; | |
const radius = this.getApothem(); | |
return { | |
transformOrigin: 'center center', | |
transform: `rotateX(${deg}deg) translateZ(${radius}px)`, | |
height: 100, | |
background: 'rgba(0,0,0,0.9)', | |
position: 'absolute', | |
width: '100%', | |
}; | |
} | |
render() { | |
const props: {songList: Song[], fullSongList: Song[], selectedSongIndex: number } = this.props; | |
function calculateStyle(index, selected) { | |
if (selected) { | |
return { | |
height: 100, | |
}; | |
} | |
if (index === 2) { | |
return { | |
opacity: 0, | |
transform: 'translateY(-50px)', | |
}; | |
} | |
return { | |
height: 0, | |
opacity: 0, | |
}; | |
} | |
return ( | |
<div className={`${styles.container} ${props.selectedSongIndex > -1 ? styles.active : ''}`}> | |
{ props.songList.map((item, i) => <div | |
id={`s${i}`} | |
style={{ | |
...props.selectedSongIndex > -1 ? calculateStyle(i, props.selectedSongIndex === item.id) : null, | |
}} | |
className={`${styles.songItem}`} | |
key={i} | |
> | |
<div | |
ref={`row_${i}`} | |
className={styles.song3dwrap} style={{ | |
transform: `translateY(-50%) translateZ(-${this.getApothem()}px) rotateX(${this.state.deg}deg)`, | |
top: '50%', | |
}} | |
> | |
<Textfit | |
style={this.calculateSongStyle(0)} | |
className={styles.songText} | |
max={48} | |
mode="single" | |
>{`${item.name} ${item.artist}`}</Textfit> | |
{this.state.shuffleList[i].map((song, j) => | |
<Textfit | |
max={48} | |
className={styles.songText} | |
style={this.calculateSongStyle(j + 1)} | |
key={`f${song.id || song.name}`} | |
>{song.name}</Textfit>)} | |
</div> | |
</div>)} | |
</div> | |
); | |
} | |
} | |
export default PlayerSongList; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment