nexshop-web-contents
Version:
Nexshop Web Contents Project
318 lines (289 loc) • 14.1 kB
JavaScript
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import ScenePreviewDetailView from "../scene/scene-preview-detail-view";
const PREVIEW_LIST_SIZE = 250;
class PlaylistPreviewDetailView extends Component {
constructor(props) {
super(props);
const previewDetailSize = {
width: props.previewWindowSize.width - PREVIEW_LIST_SIZE,
height: props.previewWindowSize.height
};
const {contentItemSize, mountDepth} = this.getPreviewBodyFrameSize(props.resolution, previewDetailSize);
this.state = {
active: false,
height: props.height,
previewDetailSize,
contentItemSize,
mountDepth
};
this.timeoutNumber = 0;
this.animate = this.animate.bind(this);
this.drawContents = this.drawContents.bind(this);
this.drawFadeImage = this.drawFadeImage.bind(this);
this.drawBlindImage = this.drawBlindImage.bind(this);
this.drawDefaultImage = this.drawDefaultImage.bind(this);
this.drawSlideImage = this.drawSlideImage.bind(this);
this.getPreviewBodyFrameSize = this.getPreviewBodyFrameSize.bind(this);
this.getContentItemEffectPoint = this.getContentItemEffectPoint.bind(this);
}
componentDidMount() {
this.animate();
}
componentWillReceiveProps() {
this.setState({active: false});
this.animate();
}
componentWillUnmount() {
clearTimeout(this.timeoutNumber);
}
animate() {
this.timeoutNumber = setTimeout(() => {
if (!this.state.active) {
this.setState({active: true});
}
}, 0);
}
getPreviewBaseSide(playlistRatio, windowRatio) {
return playlistRatio < windowRatio ? 'height' : 'width';
}
getPreviewRatio(resolution, windowSize) {
const baseSide = this.getPreviewBaseSide(resolution.width / resolution.height, windowSize.width / windowSize.height);
return windowSize[baseSide] / resolution[baseSide];
}
drawContents(contentItem, previousContentItem = {}, contentItemSize, mountDepth) {
const {contents: {metaData, type}, fitMode, transitionEffect} = contentItem;
const {contentUrl, mimeType} = metaData;
const {effectPoint} = this.getContentItemEffectPoint(contentItemSize, mountDepth);
const {contents: {metaData: {contentUrl: previousContentsUrl = ''} = {}} = {}, fitMode: previousFitMode} = previousContentItem;
if (type === 'video' && this.state.active) {
return (
<div className="preview-detail--video">
<div className="preview-detail--video__center">
<div className="preview-detail--video__wrapper">
{
<video preload="metadata" autoPlay controls
src={contentUrl} type={mimeType}
width={contentItemSize.width} height={contentItemSize.height}
style={{objectFit: `${fitMode}`}}
/>
}
</div>
</div>
</div>
);
} else if (type === 'scene' && this.state.active) {
return (
//TODO : another resolution case
<ScenePreviewDetailView scene={metaData} previewWindowSize={this.state.previewDetailSize}
sceneLayoutSize={this.props.resolution.orientation === 'horizontal' ? {
width: 960,
height: 540
} : {width: 540, height: 960}}/>
)
}
switch (transitionEffect) {
case 'fade':
return this.drawFadeImage(contentUrl, previousContentsUrl, contentItemSize, effectPoint, fitMode, previousFitMode);
case 'blind':
return this.drawBlindImage(contentUrl, previousContentsUrl, contentItemSize, mountDepth, effectPoint, fitMode, previousFitMode);
case 'slide':
return this.drawSlideImage(contentUrl, previousContentsUrl, contentItemSize, mountDepth, effectPoint, fitMode, previousFitMode);
default :
return this.drawDefaultImage(contentUrl, contentItemSize, effectPoint, fitMode);
}
}
drawSlideImage(contentUrl, previousContentUrl, contentItemSize, mountDepth, effectPoint, fitMode, previousFitMode) {
return (
<div className="preview-detail">
<div style={{
backgroundColor: 'black',
width: `${mountDepth.width}px`,
height: `${contentItemSize.height + 2 * mountDepth.height}px`,
zIndex: 2
}}/>
<div style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center'
}}>
<div className="preview-detail-image"
style={{
width: `${contentItemSize.width}px`,
height: `${contentItemSize.height}px`
}}
>
<div className={`preview-detail-slide`} style={{
top: `${effectPoint.basePoint.y}px`,
left: `${this.state.active ? effectPoint.basePoint.x : effectPoint.startPoint.x}px`,
transition: `${this.state.active ? 'left 1s' : ''}`,
backgroundSize: `${previousFitMode}`,
backgroundImage: `url(${contentUrl})`,
width: `${contentItemSize.width}px`,
height: `${contentItemSize.height}px`
}}/>
<div className={`preview-detail-slide`} style={{
top: `${effectPoint.basePoint.y}px`,
left: `${this.state.active ? effectPoint.endPoint.x : effectPoint.basePoint.x}px`,
transition: `${this.state.active ? 'left 1s' : ''}`,
backgroundSize: `${fitMode}`,
backgroundImage: `url(${previousContentUrl})`,
width: `${contentItemSize.width}px`,
height: `${contentItemSize.height}px`
}}/>
</div>
</div>
<div style={{
backgroundColor: 'black',
width: `${mountDepth.width + 1}px`,
height: `${contentItemSize.height + 2 * mountDepth.height}px`,
zIndex: 2
}}/>
</div>
);
}
drawFadeImage(contentUrl, previousContentUrl, contentItemSize, effectPoint, fitMode, previousFitMode) {
return (
<div className="preview-detail">
<div className="preview-detail-image"
style={{
width: `${contentItemSize.width}px`,
height: `${contentItemSize.height}px`
}}
>
<div className={`preview-detail-fade`} style={{
opacity: `${this.state.active ? '1' : '0'}`,
transition: `${this.state.active ? 'opacity 1s' : ''}`,
backgroundSize: `${previousFitMode}`,
backgroundImage: `url(${contentUrl})`,
top: `${effectPoint.basePoint.y}px`,
left: `${effectPoint.basePoint.x}px`,
width: `${contentItemSize.width}px`,
height: `${contentItemSize.height}px`
}}/>
<div className={`preview-detail-fade`} style={{
opacity: `${this.state.active ? '0' : '1'}`,
transition: `${this.state.active ? 'opacity 1s' : ''}`,
backgroundSize: `${fitMode}`,
backgroundImage: `url(${previousContentUrl})`,
top: `${effectPoint.basePoint.y}px`,
left: `${effectPoint.basePoint.x}px`,
width: `${contentItemSize.width}px`,
height: `${contentItemSize.height}px`
}}/>
</div>
</div>);
}
drawBlindImage(contentUrl, previousContentUrl, contentItemSize, mountDepth, effectPoint, fitMode, previousFitMode) {
return (
<div className="preview-detail"
style={{flexDirection: 'column'}}
>
<div style={{
backgroundColor: 'black',
width: `${contentItemSize.width + 2 * mountDepth.width}px`,
height: `${mountDepth.height}px`,
zIndex: 3
}}/>
<div style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center'
}}>
<div className="preview-detail-image"
style={{
width: `${contentItemSize.width}px`,
height: `${contentItemSize.height}px`
}}
>
<div className={'preview-detail-blind'} style={{
zIndex: 2,
top: `${this.state.active ? effectPoint.endPoint.y : effectPoint.basePoint.y}px`,
left: `${effectPoint.basePoint.x}px`,
visibility: `${!this.state.active}`,
overflow: 'hidden',
transition: `${this.state.active ? 'top 1s' : ''}`,
backgroundSize: `${previousFitMode}`,
backgroundImage: `url(${previousContentUrl})`,
width: `${contentItemSize.width}px`,
height: `${contentItemSize.height}px`
}}/>
<div className={`preview-detail-blind`} style={{
zIndex: 1,
backgroundSize: `${fitMode}`,
backgroundImage: `url(${contentUrl})`,
top: `${effectPoint.basePoint.y}px`,
left: `${effectPoint.basePoint.x}px`,
width: `${contentItemSize.width}px`,
height: `${contentItemSize.height}px`
}}/>
</div>
</div>
<div style={{
backgroundColor: 'black',
width: `${contentItemSize.width + 2 * mountDepth.width}px`,
height: `${mountDepth.height + 1}px`,
zIndex: 3
}}/>
</div>);
}
drawDefaultImage(contentUrl, contentItemSize, effectPoint, fitMode) {
return (
<div className="preview-detail">
<div className="preview-detail-image"
style={{
width: `${contentItemSize.width}px`,
height: `${contentItemSize.height}px`
}}>
<div className='preview-detail-default' style={{
position: 'fixed',
zIndex: 1,
backgroundSize: `${fitMode}`,
backgroundImage: `url(${contentUrl})`,
top: `${effectPoint.basePoint.y}px`,
left: `${effectPoint.basePoint.x}px`,
width: `${contentItemSize.width}px`,
height: `${contentItemSize.height}px`
}}/>
</div>
</div>);
}
getPreviewBodyFrameSize(display, previewDetailSize) {
const {text, orientation} = display;
const resolution = orientation === 'horizontal' ? {
width: text.split('x')[0],
height: text.split('x')[1]
} : {width: text.split('x')[1], height: text.split('x')[0]};
const ratio = this.getPreviewRatio(resolution, previewDetailSize);
let contentItemSize = {
width: Math.round(ratio * resolution.width),
height: Math.round(ratio * resolution.height)
};
let mountDepth = {
width: Math.floor((previewDetailSize.width - contentItemSize.width) / 2),
height: Math.floor((previewDetailSize.height - contentItemSize.height) / 2)
};
return {contentItemSize, mountDepth};
}
getContentItemEffectPoint(contentItemSize, mountDepth) {
const basePoint = {x: (PREVIEW_LIST_SIZE + mountDepth.width), y: (mountDepth.height)};
const startPoint = {x: (basePoint.x + contentItemSize.width), y: (basePoint.y - contentItemSize.height)};
const endPoint = {x: (basePoint.x - contentItemSize.width), y: (basePoint.y + contentItemSize.height)};
return {effectPoint: {basePoint, startPoint, endPoint}};
}
render() {
const {contentItem, previousContentItem} = this.props;
const {contentItemSize, mountDepth} = this.state;
return (
<div ref="preview">
{
this.drawContents(contentItem, previousContentItem, contentItemSize, mountDepth)
}
</div>
);
}
}
PlaylistPreviewDetailView.propTypes = {
contentItem: PropTypes.object.isRequired,
};
export default PlaylistPreviewDetailView;