showcases/ascii/components/control-panel.js (131 lines of code) (raw):
/* global document */
import React, {PureComponent} from 'react';
import {MIN_SIZE_SCALE, MAX_SIZE_SCALE, FONTS, VIDEOS} from './constants';
export default class ControlPanel extends PureComponent {
constructor(props) {
super(props);
this._onKeydown = this._onKeydown.bind(this);
this._setVideoSource = this._setVideoSource.bind(this);
this._togglePlay = this._togglePlay.bind(this);
this._onVideoSourceChange = this._onVideoSourceChange.bind(this);
this._onSizeScaleChange = this._onSizeScaleChange.bind(this);
this._onFontFamilyChange = this._onFontFamilyChange.bind(this);
}
componentDidMount() {
document.addEventListener('keydown', this._onKeydown);
}
componentWillReceiveProps(nextProps) {
if (nextProps.video && !this.props.video) {
// video element is just loaded
this._setVideoSource(nextProps.video, nextProps.videoSource);
}
}
componentWillUnmount() {
document.removeEventListener('keydown', this._onKeydown);
}
_onKeydown(event) {
switch (event.keyCode) {
case 38:
// up: increase font size
this._nextSizeScale(1);
break;
case 40:
// down: reduce font size
this._nextSizeScale(-1);
break;
case 32:
// spacebar: toggle playback
this._togglePlay();
break;
case 39:
// right: use next video
this._nextVieoSource(1);
break;
case 37:
// left: use prev video
this._nextVieoSource(-1);
break;
default:
}
}
_togglePlay() {
const isPlaying = !this.props.isPlaying;
this.props.video[isPlaying ? 'play' : 'pause']();
this.props.updateSettings({isPlaying});
}
_nextSizeScale(delta) {
let {sizeScale} = this.props;
sizeScale *= Math.pow(2, delta / 2);
if (sizeScale < MIN_SIZE_SCALE) {
sizeScale = MIN_SIZE_SCALE;
}
if (sizeScale > MAX_SIZE_SCALE) {
sizeScale = MAX_SIZE_SCALE;
}
this.props.updateSettings({sizeScale});
}
_nextVieoSource(delta) {
let {videoSource} = this.props;
videoSource = (videoSource + delta + VIDEOS.length) % VIDEOS.length;
this._setVideoSource(this.props.video, videoSource);
this.props.updateSettings({isPlaying: true, videoSource});
}
_setVideoSource(video, sourceIndex) {
const videoSourceInfo = VIDEOS[sourceIndex];
switch (typeof videoSourceInfo.source) {
case 'function':
videoSourceInfo.source(obj => {
video.srcObject = obj;
});
break;
case 'string':
video.srcObject = null;
video.src = videoSourceInfo.source;
break;
default:
video.srcObject = videoSourceInfo.source;
}
video.play();
}
_onVideoSourceChange(event) {
const videoSource = event.target.value;
this._setVideoSource(this.props.video, videoSource);
this.props.updateSettings({isPlaying: true, videoSource});
}
_onSizeScaleChange(event) {
this.props.updateSettings({
sizeScale: Math.pow(2, event.target.value)
});
}
_onFontFamilyChange(event) {
this.props.updateSettings({
fontFamily: event.target.value
});
}
render() {
const {fontFamily, isPlaying, videoSource, sizeScale} = this.props;
const videoSourceInfo = VIDEOS[videoSource];
return (
<div className="control-panel">
<div onClick={this._togglePlay} className={`button ${isPlaying ? 'pause' : 'play'}`} />
<div>
{videoSourceInfo.name}
<i>{videoSourceInfo.description}</i>
</div>
<div>
<label>Video Source</label>
<select value={videoSource} onChange={this._onVideoSourceChange}>
{VIDEOS.map((v, i) => (
<option key={i} value={i}>
{v.name}
</option>
))}
</select>
</div>
<div>
<label>Font Family</label>
<select value={fontFamily} onChange={this._onFontFamilyChange}>
{FONTS.map(f => (
<option key={f} value={f}>
{f.replace(/"/g, '')}
</option>
))}
</select>
</div>
<div>
<label>Font Size</label>
<input
type="range"
value={Math.log2(sizeScale)}
min={-3}
max={2}
step={0.5}
onInput={this._onSizeScaleChange}
/>
</div>
</div>
);
}
}