UNPKG

nexshop-web-contents

Version:

Nexshop Web Contents Project

318 lines (289 loc) 14.1 kB
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;